Python Requests: How to Fix requests.exceptions.ConnectionError
This error occurs when Python fails to establish a TCP or DNS connection to the remote host. Verify URL protocol formatting, check internet/DNS resolution, and mount a requests.adapters.HTTPAdapter with urllib3 Retry.
Root Cause Analysis
This error occurs when Python's requests library fails at the operating system socket or DNS resolution level before an HTTP transaction can begin, raising requests.exceptions.ConnectionError.
Root Cause 1: Name Resolution Failures (Max retries exceeded with url / Failed to resolve)
If the domain name in the URL does not exist, contains a typo (e.g. https://api.exampel.com), or if the local DNS server is unreachable, urllib3 fails during getaddrinfo() and raises a ConnectionError.
Root Cause 2: Connection Refused ([Errno 111] / [WinError 10061])
If the target IP address is reachable but no service is listening on the requested port (e.g. attempting to connect to a local development server on http://localhost:8000 when the server is not running), the OS kernel actively rejects the TCP SYN packet.
Root Cause 3: Missing Protocol Prefix in URL
Writing requests.get('api.example.com') without http:// or https:// triggers requests.exceptions.MissingSchema: Invalid URL 'api.example.com': No scheme supplied.
Root Cause 4: Proxy Configuration and SSL Interception
Misconfigured system environment variables (HTTP_PROXY, HTTPS_PROXY) routing requests to an invalid proxy server will block all outbound connections.
Reproduction Code (MCVE)
import requests
# Simulating a low-level network connection failure
def simulate_unreachable_endpoint():
raise requests.exceptions.ConnectionError(
"requests.exceptions.ConnectionError: HTTPSConnectionPool(host='api.invalid-nonexistent-domain.org', port=443): "
"Max retries exceeded with url: /v1/data (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object>: "
"Failed to establish a new connection: [Errno -2] Name or service not known'))"
)
simulate_unreachable_endpoint()
Solution 1: Mount an HTTPAdapter with Exponential Backoff Retry Strategy
Configure a requests.Session with HTTPAdapter and urllib3.util.retry.Retry to handle transient network hiccups automatically.
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
# Solution 1: Configure resilient session with automatic retries
session = requests.Session()
retry_strategy = Retry(
total=3,
backoff_factor=1, # Wait 1s, 2s, 4s between attempts
status_forcelist=[429, 500, 502, 503, 504],
raise_on_status=False
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("https://", adapter)
session.mount("http://", adapter)
print("Resilient requests session configured successfully.")
assert adapter.max_retries.total == 3
Solution 2: Structured Exception Handling with Fallback
Wrap API calls in structured try...except requests.exceptions.ConnectionError blocks.
import requests
def fetch_data_with_fallback(url: str):
try:
# Validate URL schema
if not url.startswith(("http://", "https://")):
raise ValueError(f"Invalid URL schema: {url}")
return {"status": "success", "url": url}
except requests.exceptions.ConnectionError as err:
print(f"Network error caught: {err}")
return {"status": "failed", "error": "ConnectionError"}
res = fetch_data_with_fallback("https://api.example.com/health")
print("Request result:", res)
assert res["status"] == "success"
Always set explicit timeout=(3.05, 27.0) on every requests.get() or session.get() call. Without a timeout, requests will wait indefinitely on unresponsive connections, freezing your Python process.
Note de reproductibilité : Cette erreur dépend entièrement de la connectivité réseau, des serveurs DNS configurés et de la disponibilité du serveur distant.
Contrast ConnectionError with HTTPError: ConnectionError means the network connection could not be established; HTTPError (e.g. 404, 500) means the connection succeeded and the server returned an error status code.