encode/httpx · error · InvalidURL
Invalid IPv6 address: {host!r}
Error message
Invalid IPv6 address: {host!r} What it means
Raised by encode_host when the host is bracketed ([...]) indicating an IPv6 literal but ipaddress.IPv6Address() rejects the inner text. httpx expects the RFC3986 form '[address]' with a valid IPv6 inside; malformed addresses (bad hex, wrong group count, bad '::' usage) trigger InvalidURL.
Source
Thrown at httpx/_urlparse.py:376
try:
ipaddress.IPv4Address(host)
except ipaddress.AddressValueError:
raise InvalidURL(f"Invalid IPv4 address: {host!r}")
return host
elif IPv6_STYLE_HOSTNAME.match(host):
# Validate IPv6 hostnames like [...]
#
# From https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.2
#
# "A host identified by an Internet Protocol literal address, version 6
# [RFC3513] or later, is distinguished by enclosing the IP literal
# within square brackets ("[" and "]"). This is the only place where
# square bracket characters are allowed in the URI syntax."
try:
ipaddress.IPv6Address(host[1:-1])
except ipaddress.AddressValueError:
raise InvalidURL(f"Invalid IPv6 address: {host!r}")
return host[1:-1]
elif host.isascii():
# Regular ASCII hostnames
#
# From https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.2
#
# reg-name = *( unreserved / pct-encoded / sub-delims )
WHATWG_SAFE = '"`{}%|\\'
return quote(host.lower(), safe=SUB_DELIMS + WHATWG_SAFE)
# IDNA hostnames
try:
return idna.encode(host.lower()).decode("ascii")
except idna.IDNAError:
raise InvalidURL(f"Invalid IDNA hostname: {host!r}")
View on GitHub (pinned to b5addb64f0)
Solutions
- Validate with ipaddress.IPv6Address(host.strip('[]')) before constructing the URL.
- Use a single '::' shorthand; expand the address if unsure.
- For zone IDs (link-local), percent-encode: 'fe80::1%25eth0' inside the brackets.
- Generate IPv6 literals from ipaddress output rather than string concatenation.
Example fix
// before
url = httpx.URL("http://[fe80::1zz]/") # Invalid IPv6 address
// after
import ipaddress
ipaddress.IPv6Address("fe80::1") # validate first
url = httpx.URL("http://[fe80::1]/") Defensive patterns
Strategy: validation
Validate before calling
import ipaddress
def safe_ipv6(host: str) -> str:
inner = host.strip("[]")
ipaddress.IPv6Address(inner) # raises AddressValueError early
return f"[{inner}]"
url = httpx.URL(host=safe_ipv6(user_ipv6)) Type guard
import ipaddress
def is_valid_ipv6(host: str) -> bool:
try:
ipaddress.IPv6Address(host.strip("[]"))
return True
except ipaddress.AddressValueError:
return False Try / catch
from httpx import InvalidURL
try:
url = httpx.URL(f"http://[{ipv6}]/")
except InvalidURL as e:
if "Invalid IPv6" in str(e):
raise ValueError(f"Bad IPv6 literal: {ipv6!r}") from e
raise Prevention
- Always wrap IPv6 literals in brackets for URLs.
- Use ipaddress.IPv6Address to validate before constructing URLs.
- Use at most one '::' in abbreviated addresses.
When it happens
Trigger: httpx.URL('http://[fe80::1zz]/'), httpx.URL(host='[1234::5678::9abc]') (two '::'), or host='[::g]'.
Common situations: Hand-typing IPv6 literals; truncating or pasting partial addresses; forgetting that '::' may appear only once; mixing zone identifiers without '%25' encoding.
Related errors
- Invalid IPv4 address: {host!r}
- Proxy protocol must be either 'http', 'https', 'socks5', or
- URL too long
- Invalid non-printable ASCII character in URL, {char!r} at po
- URL component '{key}' too long
AI-assisted analysis of encode/httpx@b5addb64f0 (2026-08-04).
Data as JSON: /data/errors/84d26d9268c85597.json.
Report an issue: GitHub.