psf/requests · error · ConnectionError

{err}

Error message

{err}

What it means

This is the catch-all mapping of low-level transport errors to requests' ConnectionError. When conn.urlopen raises a urllib3 ProtocolError or a builtin OSError (e.g. socket-level ECONNREFUSED, EAI_AGAIN DNS failure, broken pipe), the adapter wraps it as ConnectionError(err, request=request). It indicates the request never produced a usable response due to a network/transport failure.

Source

Thrown at src/requests/adapters.py:711

            resolved_timeout = TimeoutSauce(connect=timeout, read=timeout)

        try:
            resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,  # type: ignore[arg-type]  # urllib3 stubs don't accept Iterable[bytes | str]
                headers=request.headers,  # type: ignore[arg-type]  # urllib3#3072
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=resolved_timeout,
                chunked=chunked,
            )

        except (ProtocolError, OSError) as err:
            raise ConnectionError(err, request=request)

        except MaxRetryError as e:
            if isinstance(e.reason, ConnectTimeoutError):
                # TODO: Remove this in 3.0.0: see #2811
                if not isinstance(e.reason, NewConnectionError):
                    raise ConnectTimeout(e, request=request)

            if isinstance(e.reason, ResponseError):
                raise RetryError(e, request=request)

            if isinstance(e.reason, _ProxyError):
                raise ProxyError(e, request=request)

            if isinstance(e.reason, _SSLError):
                # This branch is for urllib3 v1.22 and later.
                raise SSLError(e, request=request)

            raise ConnectionError(e, request=request)

View on GitHub (pinned to 8068356288)

Solutions

  1. Retry with backoff for transient errors (ConnectionError often resolves on retry); use urllib3 Retry or tenacity.
  2. Verify the host resolves and is reachable (socket.getaddrinfo, a manual curl) to distinguish DNS from firewall issues.
  3. Check proxy configuration if the failure mentions a proxy.
  4. Increase the connect timeout if the error is timeout-adjacent; capture e.args for the underlying errno.
  5. For production, wrap requests calls in a retry decorator that targets ConnectionError and ReadTimeout.

Example fix

# before
resp = requests.get(url)  # intermittent ConnectionError

# after
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

s = requests.Session()
retry = Retry(total=3, backoff_factor=0.3,
              status_forcelist=[502, 503, 504])
s.mount("https://", HTTPAdapter(max_retries=retry))
resp = s.get(url)
Defensive patterns

Strategy: retry

Validate before calling

import socket

def preflight_host(url: str, timeout: float = 5.0) -> None:
    """Resolve + TCP-connect to the host to fail fast on DNS/firewall issues."""
    from urllib.parse import urlparse
    p = urlparse(url)
    host = p.hostname
    port = p.port or (443 if p.scheme == "https" else 80)
    try:
        socket.getaddrinfo(host, port, type=socket.SOCK_STREAM)
    except socket.gaierror as e:
        raise ConnectionError(f"DNS resolution failed for {host}: {e}") from e

preflight_host(url)

Type guard

# ConnectionError is a runtime/network failure; the relevant guard is a
# reachability check rather than a type narrowing.
def is_host_reachable(host: str, port: int, timeout: float = 3.0) -> bool:
    import socket
    try:
        with socket.create_connection((host, port), timeout=timeout):
            return True
    except OSError:
        return False

Try / catch

import time
import requests.exceptions as exc

def get_with_retry(session, url, attempts=3, backoff=0.5):
    last = None
    for i in range(attempts):
        try:
            return session.get(url)
        except exc.ConnectionError as e:
            last = e
            time.sleep(backoff * (2 ** i))
    raise last

Prevention

When it happens

Trigger: Triggered by any OSError or urllib3.exceptions.ProtocolError during the urlopen call: DNS resolution failure, connection refused, network unreachable, TCP reset, broken pipe, or a proxy protocol violation. Fires after the connection is obtained and the request is dispatched.

Common situations: Seen during transient network blips, when the target host is down or DNS is flaky, when a firewall drops the connection, when a proxy returns malformed responses, or in containers with misconfigured DNS (e.g. resolving an internal host that is not resolvable).

Related errors


AI-assisted analysis of psf/requests@8068356288 (2026-08-11). Data as JSON: /api/errors/e5f1ca20c4fc8508. Report an issue: GitHub.