Skip to main content

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 number errno.ECONNRESET (which corresponds to 104 on many systems).
  • In Python 3.3+, the more specific ConnectionResetError (which inherits from OSError) 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.

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 that requests often wraps lower-level errors, so catching requests.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 or while 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}")
note

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 (or tracert on Windows), and mtr 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

  1. Reproducibility: Can you consistently reproduce the error? Does it happen only under load or at specific times?
  2. Target: Does it happen only with one specific server/URL, or multiple?
  3. Environment: Does it happen in different network environments (e.g., home vs. office vs. cloud VM)?
  4. Logging: Add detailed logging within your try...except blocks to capture the context when the error occurs.
  5. 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 checking errno.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.