psf/requests · error · InvalidURL

URL has an invalid label.

Error message

URL has an invalid label.

What it means

Raised by PreparedRequest.prepare_url when the host contains non-ASCII characters and the IDNA encoding step (_get_idna_encoded_host) raises UnicodeError. IDNA encoding converts internationalized domain names to punycode; if a label violates IDNA rules (overlong label, invalid characters, disallowed joiners), encoding fails and requests surfaces it as InvalidURL. This guards against sending unresolvable hostnames.

Solutions

  1. Pre-validate the hostname with encodings.idna.ToASCII (or idna.encode) in a try/except and reject invalid inputs before calling requests.
  2. Shorten labels to <=63 characters and remove unsupported characters.
  3. If the domain is genuinely valid IDNA, ensure you pass the Unicode form (not a half-encoded punycode mix) and let requests do the encoding.

Example fix

// before
requests.get('https://exa' + 'm'*70 + 'mple.com/path')

// after
host = 'exa' + 'm'*70 + 'mple.com'
try:
    import idna
    host = idna.encode(host).decode('ascii')
except idna.IDNAError:
    raise ValueError(f'invalid host: {host!r}')
requests.get(f'https://{host}/path')
Defensive patterns

Strategy: validation

Validate before calling

import idna

def is_idna_valid(host: str) -> bool:
    try:
        idna.encode(host)
        return True
    except idna.IDNAError:
        return False

Type guard

import idna
from typing import Union

def valid_idna_host(host: str) -> Union[str, None]:
    """Return punycode host if valid, else None."""
    try:
        return idna.encode(host).decode('ascii')
    except idna.IDNAError:
        return None

Try / catch

from requests.exceptions import InvalidURL

try:
    resp = requests.get(f'https://{host}/path')
except InvalidURL as e:
    if 'invalid label' in str(e):
        # reject or sanitize the hostname
        ...
    raise

Prevention

When it happens

Trigger: Passing a Unicode hostname with an illegal label — e.g. labels longer than 63 chars, empty labels, or characters disallowed by IDNA 2008; hostnames with zero-width joiners or other unsupported Unicode; mixed RTL/LTR scripts.

Common situations: User-entered internationalized domains that look valid but violate IDNA length/character rules; data-entry from locales with characters outside IDNA's allowed set; truncation that splits a label mid-codepoint.

Related errors


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

Appendix: source

Thrown at src/requests/models.py:532

        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
        if port:
            netloc += f":{port}"

        # Bare domains aren't valid URLs.
        if not path:
            path = "/"

        if isinstance(params, (str, bytes)):
            params = to_native_string(params)

View on GitHub (pinned to 8068356288)