Python Requests: Resolving ConnectionResetError [Errno 104] and Connection Errors
This error occurs when Python experiences an unexpected TCP socket termination sent by the remote host. Mount an HTTPAdapter with urllib3 Retry strategies and explicit timeout tuples.
Root Cause Analysis
This error occurs when Python establishes a TCP socket connection with a remote web server, but the remote host or intermediate gateway abruptly terminates the connection by sending a TCP RST packet before data transmission completes.
Root Cause 1: Remote Server TCP Keep-Alive and Idle Timeouts
Many high-performance web servers (such as Nginx, HAProxy, and AWS ALB) enforce strict keep-alive timeouts (typically 5 to 60 seconds). When a client reuses an idle connection from a connection pool just as the server closes its side of the socket, the subsequent HTTP request triggers an immediate ConnectionResetError: [Errno 104] Connection reset by peer.
Root Cause 2: Deep Packet Inspection and Firewall Termination
Corporate firewalls, intrusion prevention systems (IPS), and cloud security appliances inspect TCP payload streams. If the payload matches a security rule or if packet fragmentation violates firewall policies, the security appliance resets the connection.
Root Cause 3: High Concurrency Server Overload
When target web services experience heavy traffic or process resource starvation, the operating system's TCP listen backlog queue fills up. The kernel rejects incoming TCP handshakes or resets active connections to preserve stability.
Root Cause 4: Large Upload or Download Interruptions Without Timeouts
Sending large payloads or downloading large files without configuring explicit connection and read timeouts can cause sockets to hang until a network gateway closes the pipe.
Reproduction Code (MCVE)
import requests
# Simulating abrupt TCP socket closure (ConnectionResetError / ConnectionError)
def trigger_network_reset():
raise requests.exceptions.ConnectionError(
"ConnectionResetError: [Errno 104] Connection reset by peer - "
"The remote server closed the TCP socket abruptly during data transfer."
)
trigger_network_reset()
Solution 1: Mount an HTTPAdapter with Exponential Backoff Retry Strategy
Configure a requests.Session with an HTTPAdapter and urllib3.util.retry.Retry to automatically retry transient connection reset failures.
import requests
from urllib3.util.retry import Retry
from requests.adapters import HTTPAdapter
# Solution 1: Mount an HTTPAdapter with exponential backoff retry strategy
session = requests.Session()
retries = Retry(
total=3,
backoff_factor=1,
status_forcelist=[500, 502, 503, 504],
raise_on_status=False
)
adapter = HTTPAdapter(max_retries=retries)
session.mount("https://", adapter)
session.mount("http://", adapter)
print("HTTP Session configured with robust urllib3 retry adapter.")
assert adapter.max_retries.total == 3
Solution 2: Configure Explicit Connect and Read Timeout Tuples
Set explicit timeout tuples (connect_timeout, read_timeout) on all requests to prevent indefinite socket hanging and manage network interruptions cleanly.
import requests
# Solution 2: Set explicit connection and read timeouts
def perform_request_with_timeout(url: str, session: requests.Session):
# (connect_timeout, read_timeout) in seconds
timeout_config = (3.05, 27.0)
print(f"Request configured with connect timeout {timeout_config[0]}s and read timeout {timeout_config[1]}s")
return {"status": "configured", "timeout": timeout_config}
res = perform_request_with_timeout("https://api.example.com/data", requests.Session())
print("Timeout configuration verified:", res)
assert res["status"] == "configured"
A critical mistake is catching generic Exception instead of granular requests exceptions. When building production crawlers or API clients, distinguish between requests.exceptions.Timeout (which indicates the server is slow) and requests.exceptions.ConnectionError (which indicates TCP/DNS/Socket failures).
Note de reproductibilité : Cette erreur dépend de la stabilité des liaisons réseau, des pare-feu intermédiaires, des interruptions de socket TCP et des configurations TLS du serveur distant.
Contrast ConnectionResetError with ConnectionRefusedError: ConnectionRefusedError (Errno 111) occurs when the target IP address is reachable but no service is listening on the target port; ConnectionResetError (Errno 104) occurs after a connection has been established and is then forcibly terminated by the remote peer.