Main Ecosystems
HomePython CorePandas ReferenceNumPy ScientificFastAPI & PydanticDjango Enterprise
More Ecosystems
Environment & SetupRequests & HTTPAsyncIO ConcurrencyObject-Oriented OOPPyTorch Deep LearningScikit-Learn MLFlask FrameworkWeb ScrapingDatabase & ORMDevOps & Docker

Python Requests: How to Fix requests.exceptions.ConnectionError

Verified FixPython 3.10+Requests 2.31+, urllib3 2.0+Silo: requests

Quick Fix / Solution Rapide

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)

Example: Bug Reproduction
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.

Example: Recommended Solution
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.

Example: Alternative Solution
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.