psf/requests · error · InvalidURL

{e}

Error message

{e}

What it means

This is a re-raise of a ValueError from build_connection_pool_key_attributes as an InvalidURL, attaching the request. The underlying ValueError comes from urllib3/requests connection-key construction (e.g. an unparseable host, missing host, or bad port). Wrapping it as InvalidURL gives callers a consistent exception type for malformed URL problems during connection setup in get_connection_with_tls_context's caller path (send -> proxy branch).

Source

Thrown at src/requests/adapters.py:491

        :param proxies:
            (optional) The proxies dictionary to apply to the request.
        :param cert:
            (optional) Any user-provided SSL certificate to be used for client
            authentication (a.k.a., mTLS).
        :rtype:
            urllib3.HTTPConnectionPool
        """
        assert _is_prepared(request)

        proxy = select_proxy(request.url, proxies)
        try:
            host_params, pool_kwargs = self.build_connection_pool_key_attributes(
                request,
                verify,
                cert,
            )
        except ValueError as e:
            raise InvalidURL(e, request=request)
        if proxy:
            proxy = prepend_scheme_if_needed(proxy, "http")
            proxy_url = parse_url(proxy)
            if not proxy_url.host:
                raise InvalidProxyURL(
                    "Please check proxy URL. It is malformed "
                    "and could be missing the host."
                )
            proxy_manager = self.proxy_manager_for(proxy)
            conn = proxy_manager.connection_from_host(
                **host_params, pool_kwargs=pool_kwargs
            )
        else:
            # Only scheme should be lower case
            conn = self.poolmanager.connection_from_host(
                **host_params, pool_kwargs=pool_kwargs
            )

View on GitHub (pinned to 8068356288)

Solutions

  1. Validate the URL with requests.utils.urlparse / urllib.parse.urlparse and confirm .hostname and .port are sane before sending.
  2. Sanitize or reject URLs without a host or with non-numeric ports before they reach the adapter.
  3. If redirects are involved, inspect the response chain and reject malformed Location values.
  4. Pin/normalize the scheme to http or https and reject anything else upstream.
  5. Add a unit test that feeds your URL builder edge cases (empty host, bad port) to catch regressions.

Example fix

# before
requests.get("http://:8080/path")  # no host -> InvalidURL

# after
from urllib.parse import urlparse
u = urlparse("http://example.com:8080/path")
if not u.hostname:
    raise ValueError(f"URL has no host: {u.geturl()}")
requests.get(u.geturl())
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlparse

def assert_valid_target_url(url: str) -> str:
    """Reject URLs that would break connection-key construction."""
    p = urlparse(url)
    if not p.hostname:
        raise ValueError(f"URL has no host: {url!r}")
    if p.scheme.lower() not in ("http", "https"):
        raise ValueError(f"unsupported scheme: {p.scheme}")
    if p.port is not None and not (0 < p.port < 65536):
        raise ValueError(f"invalid port: {p.port}")
    return url

requests.get(assert_valid_target_url(url))

Type guard

from urllib.parse import urlparse

def is_valid_request_url(url) -> bool:
    if not isinstance(url, str) or not url:
        return False
    p = urlparse(url)
    if not p.hostname:
        return False
    if p.scheme.lower() not in ("http", "https"):
        return False
    if p.port is not None and not (0 < p.port < 65536):
        return False
    return True

Try / catch

import requests.exceptions as exc

try:
    resp = session.get(url)
except exc.InvalidURL as e:
    # log and reject the URL upstream rather than retrying blindly
    raise ValueError(f"refusing malformed URL {url!r}: {e}") from e

Prevention

When it happens

Trigger: Triggered when build_connection_pool_key_attributes cannot build a valid urllib3 connection key from the request URL, such as a URL with no host, an invalid port, or an unsupported scheme. It surfaces inside the send flow at the point host_params and pool_kwargs are computed, before any network activity.

Common situations: Happens with programmatically-built URLs that drop the host, with international/IDN hostnames that fail encoding, with URLs containing stray characters or bad port segments, or when a redirect chain yields an invalid Location header URL.

Related errors


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