Mensaje de error
[SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol
También se muestra como
- ssl.SSLEOFError: EOF occurred in violation of protocol
Con OpenSSL 3, Python muestra el código de motivo «[SSL: UNEXPECTED_EOF_WHILE_READING]»; con OpenSSL 1.1.1, el texto es solo «EOF occurred in violation of protocol». Le sigue una ubicación en el código fuente como «(_ssl.c:1082)».
Python ssl module (OpenSSL) — ssl.SSLEOFError, SSL_R_UNEXPECTED_EOF_WHILE_READING
Qué significa
El otro extremo cerró la conexión TCP mientras Python seguía en el handshake TLS (o a mitad de la lectura de datos), sin enviar una alerta TLS ni close_notify. OpenSSL trata ese cierre silencioso como una violación del protocolo. Python no puede saber por qué se fue el otro extremo; el motivo está en el servidor, en un proxy o en un firewall intermedio.
Por qué ocurre
El servidor corta los handshakes que no le gustan
frecuenteAlgunos servidores y balanceadores de carga cierran la conexión en lugar de enviar una alerta cuando el ClientHello no incluye SNI, no ofrece ninguna versión ni ningún cifrado aceptables, o el nombre no está configurado.
Un proxy, un firewall o una VPN corta la conexión
frecuenteUna configuración de proxy incorrecta (HTTPS_PROXY que apunta a un puerto TLS del proxy, falta de NO_PROXY para los hosts internos), la inspección profunda de paquetes que bloquea el destino o los clientes VPN suelen terminar la conexión TCP en silencio.
Limitación de frecuencia o protección contra bots
ocasionalLas API y las CDN con mucha carga, o los sistemas de protección contra bots a los que no les gusta la huella TLS de Python, pueden restablecer las conexiones en lugar de devolver un error HTTP.
El servidor cerró la conexión a mitad de la respuesta
ocasionalSi el error se produce mientras se lee una respuesta, el servidor o un proxy terminó la conexión sin close_notify, por ejemplo, tras agotarse un tiempo de espera o caerse un proceso de trabajo.
Cómo solucionarlo
- 1.
Reproducir el handshake con openssl s_client
Si s_client también se desconecta, cambia el SNI y la versión de TLS para ver qué rechaza el servidor; si s_client funciona, compara su configuración con la de tu cliente Python (proxy, SNI, versiones).
bash # Does a plain OpenSSL handshake work from the same machine? openssl s_client -connect api.example.com:443 -servername api.example.com -brief </dev/null # Without SNI, and pinned to TLS 1.2, to see what the server objects to openssl s_client -connect api.example.com:443 -noservername -brief </dev/null openssl s_client -connect api.example.com:443 -servername api.example.com -tls1_2 -brief </dev/null - 2.
Comprobar las variables de entorno del proxy
requests, urllib y pip respetan HTTPS_PROXY y NO_PROXY. Corrige el esquema de la URL del proxy y excluye los hosts internos a los que hay que llegar directamente.
bash env | grep -i -E '^(https?|no|all)_proxy=' # Proxy URLs should normally be http:// (CONNECT tunnel), and internal hosts listed in NO_PROXY export HTTPS_PROXY=http://proxy.example.net:3128 export NO_PROXY=localhost,127.0.0.1,.internal.example.com - 3.
Reintentar cuando la causa es transitoria
Ante la limitación de frecuencia y las redes inestables, los reintentos con espera progresiva (backoff) convierten los cortes esporádicos en éxitos más lentos; no arreglan un servidor que siempre rechaza el handshake.
python import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry session = requests.Session() session.mount("https://", HTTPAdapter(max_retries=Retry(total=3, backoff_factor=1))) session.get("https://api.example.com/")
Errores relacionados
[SSL: WRONG_VERSION_NUMBER] wrong version numberPython ssl module (OpenSSL)curl: (56) OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while…curl (OpenSSL 3 backend)error:0A000126:SSL routines::unexpected eof while readingOpenSSL 3Client network socket disconnected before secure TLS connection was establishedNode.js tls / https / fetch