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
- Pre-validate the hostname with encodings.idna.ToASCII (or idna.encode) in a try/except and reject invalid inputs before calling requests.
- Shorten labels to <=63 characters and remove unsupported characters.
- 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
- Validate internationalized hostnames with idna.encode before sending.
- Keep DNS labels <=63 characters.
- Reject hostnames with disallowed Unicode characters upstream.
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
- {e.args}
- Invalid percent-escape sequence
- Invalid URL : No host supplied
- {e}
- Invalid URL : No scheme supplied. Perhaps you meant…
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)