How to Resolve Python Error "socket.error: [Errno 104] Connection reset by peer"
When performing network operations in Python using modules like socket
, urllib.request
, or requests
, you might encounter socket.error: [Errno 104] Connection reset by peer
(or its more specific subclass ConnectionResetError
). This error indicates that the connection was unexpectedly closed by the remote server or an intermediary device, often before or during the data exchange.
This guide explains the common causes of this network error and provides robust strategies for handling and mitigating it in your Python code.
Understanding "Connection reset by peer" (ECONNRESET / Errno 104)
At the network level, this error typically means your client received a TCP packet with the RST
(Reset) flag set from the other end (the "peer"). This is an abrupt way for the peer to terminate the connection, indicating it's no longer willing or able to participate in the established connection or that the connection attempt was invalid from its perspective. It bypasses the standard graceful TCP closing handshake (FIN/ACK).
In Python:
- This often manifests as
socket.error
with the error numbererrno.ECONNRESET
(which corresponds to 104 on many systems). - In Python 3.3+, the more specific
ConnectionResetError
(which inherits fromOSError
) is usually raised and is preferred for catching.
Common Causes of Connection Resets
Several factors can lead to the peer resetting the connection:
- Server Application Crash/Restart: The server process handling your connection might have crashed or been restarted unexpectedly.
- Server Overload: The server might be too busy to handle your request and simply drops the connection.
- Firewall Intervention: A firewall between your client and the server (or on the server itself) might identify the traffic as suspicious or disallowed and actively reset the connection.
- Load Balancer / Proxy Issues: If you connect through a load balancer or proxy, it might have its own timeout or resource limits that cause it to reset the connection to your client, even if the backend server is fine.
- Server Closing Idle Connection: Servers often close connections that have been idle for too long to conserve resources.
- Application-Level Errors on Server: The server application might encounter an internal error while processing your request and decide to abort the connection.
- Aggressive Rate Limiting: The server might reset connections if you exceed allowed request rates.
- Network Glitches: Less commonly, transient network problems could corrupt the connection state, leading to a reset.
Solution 1: Handling the Error with try...except
(Recommended)
Since connection resets can happen due to factors outside your client's control, robust network code should anticipate and handle this error gracefully. This usually involves catching the specific exception.
Catching ConnectionResetError
This is the modern and preferred way in Python 3.3+.
import requests
import time
import random
url = 'https://httpbin.org/delay/1' # An endpoint that delays response
headers = {"User-Agent": "MyPythonClient/1.0"} # Good practice to set a User-Agent
max_retries = 3
retry_delay = 1 # seconds
for attempt in range(max_retries):
try:
print(f"Attempt {attempt + 1} to connect to {url}...")
response = requests.get(url, headers=headers, timeout=10) # 10-second timeout
response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)
print(f"Success! Status Code: {response.status_code}")
# print(response.text) # Process the response
break # Exit loop on success
except requests.exceptions.ConnectionError as e:
# requests wraps lower-level errors like ConnectionResetError
# Check if the underlying cause is ConnectionResetError
# Note: This check might need refinement depending on requests version/exact context
is_reset_error = False
if e.args and isinstance(e.args[0], requests.packages.urllib3.exceptions.ProtocolError):
if e.args[0].args and isinstance(e.args[0].args[1], ConnectionResetError):
is_reset_error = True
if is_reset_error:
print(f"ConnectionResetError occurred on attempt {attempt + 1}.")
if attempt < max_retries - 1:
wait = retry_delay * (2 ** attempt) + random.uniform(0, 1) # Exponential backoff with jitter
print(f"Retrying in {wait:.2f} seconds...")
time.sleep(wait)
else:
print("Max retries reached. Failing.")
# Handle final failure (e.g., log, raise custom exception)
raise # Or raise custom error
else:
# It was a different ConnectionError (e.g., DNS error, Refused)
print(f"A non-reset ConnectionError occurred: {e}")
raise # Re-raise other connection errors immediately
except requests.exceptions.Timeout:
print("Request timed out.")
# Handle timeout specifically (might not warrant retry)
break
except requests.exceptions.RequestException as e:
# Handle other requests errors (e.g., HTTPError from raise_for_status)
print(f"An error occurred: {e}")
break # Or retry depending on the error type
- This example uses
requests
. Note thatrequests
often wraps lower-level errors, so catchingrequests.exceptions.ConnectionError
and inspecting its cause might be needed. - The
except ConnectionResetError:
block allows you to implement specific logic for this scenario (e.g., logging, retrying).
Catching socket.error
and Checking errno
(Legacy/Broader)
For compatibility or if working directly with socket
or older urllib
code, you might catch socket.error
and check the errno
attribute.
import socket
import errno
import time
# Example with low-level socket (conceptual)
target_host = "example.com"
target_port = 80 # HTTP
try:
# sock = socket.create_connection((target_host, target_port), timeout=5)
# print("Socket connected")
# sock.sendall(b'GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n')
# data = sock.recv(1024)
# print(f"Received: {data.decode('utf-8', errors='ignore')}")
# sock.close()
# --- Simulate error for demonstration ---
raise socket.error(errno.ECONNRESET, "Simulated connection reset")
# --- End simulation ---
except socket.error as err:
if err.errno == errno.ECONNRESET:
# ✅ Handle the specific connection reset error
print("Handling ConnectionResetError (ECONNRESET)")
# Add retry logic, logging, etc.
else:
# It's a different socket error
print(f"Caught a different socket error: {err}")
raise # Re-raise other socket errors
except Exception as e:
print(f"Caught a non-socket error: {e}")
- Import
errno
. - Check
if err.errno == errno.ECONNRESET:
.
Solution 2: Implement Retries with Delays
Since connection resets can be transient (e.g., temporary network issues, brief server overload), automatically retrying the request after a short delay is a common strategy.
- Use a Loop: Wrap your request code in a
for
orwhile
loop for a fixed number of retries. - Use
time.sleep()
: Pause execution between retries. - Implement Backoff: Increase the delay after each failed attempt (e.g., exponential backoff) to avoid hammering a potentially overloaded server. Add jitter (a small random delay) to prevent multiple clients retrying simultaneously.
Solution 3: Setting Request Headers (e.g., User-Agent)
Some servers might be configured to reject or throttle traffic that doesn't look like it's coming from a standard web browser. While less common as a direct cause for resets (more likely for blocks or different errors), identifying your client with a standard User-Agent
header is generally good practice and might help in some edge cases.
import requests
url = 'http://example.com' # Target URL
headers = {
# Mimic a common browser User-Agent
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36'
}
try:
response = requests.get(url, headers=headers, timeout=10)
print(f"Request successful with User-Agent. Status: {response.status_code}")
except ConnectionResetError: # Or requests.exceptions.ConnectionError
print("Connection reset even with User-Agent.")
except Exception as e:
print(f"An error occurred: {e}")
This is not a guaranteed fix for network-level or server-side problems causing the reset.
Solution 4: Investigate Server-Side and Network Issues
If the error persists despite client-side handling and retries, the root cause likely lies outside your script:
- Server Logs: Check the logs on the remote server for crashes, application errors, or resource exhaustion around the time the connection was reset.
- Firewalls: Examine firewall logs (both client-side and server-side, and any intermediaries) to see if connections are being blocked or reset.
- Load Balancers/Proxies: Check configurations and logs for timeouts or errors on these devices.
- Network Path: Use tools like
ping
,traceroute
(ortracert
on Windows), andmtr
to diagnose potential network instability between your client and the server. - Server Administrator: Contact the administrator of the remote server if possible; they may have insights into server load, configuration, or known issues.
Debugging Steps
- Reproducibility: Can you consistently reproduce the error? Does it happen only under load or at specific times?
- Target: Does it happen only with one specific server/URL, or multiple?
- Environment: Does it happen in different network environments (e.g., home vs. office vs. cloud VM)?
- Logging: Add detailed logging within your
try...except
blocks to capture the context when the error occurs. - Simplify: Try a minimal request using a standard tool like
curl
from the same machine to see if the issue is specific to your Python code or more general.
Conclusion
socket.error: [Errno 104] Connection reset by peer
(or ConnectionResetError
) signifies an abrupt connection closure by the remote end. While sometimes caused by transient network issues or rate limiting (addressable with retries and delays), it often points to problems on the server-side (crashes, overload, firewalls, application errors).
- The most crucial client-side action is robust error handling using
try...except ConnectionResetError
(or checkingerrno.ECONNRESET
). - Implement retries with exponential backoff for transient issues.
- Setting headers like
User-Agent
is good practice but less likely to fix fundamental reset problems. - If the error persists, investigation of the server and network path is necessary.
By combining careful error handling in your Python code with investigation of the network and server environment, you can effectively manage and resolve connection reset errors.