psf/requests · error · InvalidURL

Invalid URL : No host supplied

Error message

Invalid URL {url!r}: No host supplied

What it means

Raised by PreparedRequest.prepare_url when the URL parses with a scheme but no host component — e.g. 'https:///path' (triple slash), 'https://:443/path', or scheme-only strings like 'file:///'. The host is mandatory for HTTP(S) routing, so requests refuses. The message echoes the offending URL for diagnosis.

Solutions

  1. Ensure the host/authority segment is populated before assembling the URL.
  2. Validate with urllib.parse.urlparse(result).netloc before passing to requests.
  3. Fail fast on empty host config at app startup rather than per-request.

Example fix

// before
url = f'{scheme}:///{path}'  # triple slash, empty host
requests.get(url)

// after
assert host, 'host must be set'
url = f'{scheme}://{host}/{path}'
requests.get(url)
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlparse

def has_host(url: str) -> bool:
    return bool(urlparse(url).netloc)

Type guard

from urllib.parse import urlparse

def is_valid_http_url(url: str) -> bool:
    p = urlparse(url)
    return p.scheme in ('http', 'https') and bool(p.hostname)

Try / catch

from requests.exceptions import InvalidURL

try:
    resp = requests.get(url)
except InvalidURL as e:
    if 'No host supplied' in str(e):
        # fix and retry
        ...
    raise

Prevention

When it happens

Trigger: Triple-slash URLs from buggy templating ('https:///' + host where host is empty); URLs like 'https://:8080' with no hostname; schemes that urllib3 accepts but which carry no authority (e.g. some custom schemes).

Common situations: Building URLs from optional config fields that were left blank; service-discovery bugs returning empty hostnames; misconfigured environment variables (BASE_URL='https://').

Related errors


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

Appendix: source

Thrown at src/requests/models.py:522

        # handles RFC 3986 only.
        if ":" in url and not url.lower().startswith("http"):
            self.url = url
            return

        # Support for unicode domain names and paths.
        try:
            scheme, auth, host, port, path, query, fragment = parse_url(url)
        except LocationParseError as e:
            raise InvalidURL(*e.args)

        if not scheme:
            raise MissingSchema(
                f"Invalid URL {url!r}: No scheme supplied. "
                f"Perhaps you meant https://{url}?"
            )

        if not host:
            raise InvalidURL(f"Invalid URL {url!r}: No host supplied")

        # In general, we want to try IDNA encoding the hostname if the string contains
        # non-ASCII characters. This allows users to automatically get the correct IDNA
        # behaviour. For strings containing only ASCII characters, we need to also verify
        # it doesn't start with a wildcard (*), before allowing the unencoded hostname.
        if not unicode_is_ascii(host):
            try:
                host = self._get_idna_encoded_host(host)
            except UnicodeError:
                raise InvalidURL("URL has an invalid label.")
        elif host.startswith(("*", ".")):
            raise InvalidURL("URL has an invalid label.")

        # Carefully reconstruct the network location
        netloc = auth or ""
        if netloc:
            netloc += "@"
        netloc += host

View on GitHub (pinned to 8068356288)