encode/httpx · error · InvalidURL
Relative URLs cannot have a path starting with ':'
Error message
Relative URLs cannot have a path starting with ':'
What it means
Raised by validate_path when a relative URL (no scheme, no authority) starts with ':'. RFC 3986 §4.2 forbids the first path segment of a relative-path reference from containing a colon, because ':' would be ambiguous with a scheme delimiter. httpx rejects a leading ':' outright.
Source
Thrown at httpx/_urlparse.py:444
See https://datatracker.ietf.org/doc/html/rfc3986.html#section-3.3
"""
if has_authority:
# If a URI contains an authority component, then the path component
# must either be empty or begin with a slash ("/") character."
if path and not path.startswith("/"):
raise InvalidURL("For absolute URLs, path must be empty or begin with '/'")
if not has_scheme and not has_authority:
# If a URI does not contain an authority component, then the path cannot begin
# with two slash characters ("//").
if path.startswith("//"):
raise InvalidURL("Relative URLs cannot have a path starting with '//'")
# In addition, a URI reference (Section 4.1) may be a relative-path reference,
# in which case the first path segment cannot contain a colon (":") character.
if path.startswith(":"):
raise InvalidURL("Relative URLs cannot have a path starting with ':'")
def normalize_path(path: str) -> str:
"""
Drop "." and ".." segments from a URL path.
For example:
normalize_path("/path/./to/somewhere/..") == "/path/to"
"""
# Fast return when no '.' characters in the path.
if "." not in path:
return path
components = path.split("/")
# Fast return when no '.' or '..' components in the path.
if "." not in components and ".." not in components:View on GitHub (pinned to b5addb64f0)
Solutions
- Prefix the path with './' to disambiguate: httpx.URL('./:foo').
- Supply a scheme so the URL is absolute.
- Strip or reject leading colons in user-supplied relative paths.
- Use urljoin against a base URL rather than constructing relative URLs by hand.
Example fix
// before
url = httpx.URL(":foo") # InvalidURL
// after
url = httpx.URL("./:foo") # or provide a full URL Defensive patterns
Strategy: validation
Validate before calling
def disambiguate_relative(path: str) -> str:
if path.startswith(":"):
return "./" + path
return path
url = httpx.URL(disambiguate_relative(user_path)) Type guard
def relative_path_is_safe(path: str) -> bool:
return not path.startswith(":") Try / catch
from httpx import InvalidURL
try:
url = httpx.URL(p)
except InvalidURL as e:
if "cannot have a path starting with ':'" in str(e):
url = httpx.URL("./" + p)
else:
raise Prevention
- Prefix ':'-leading relative paths with './'.
- Supply a scheme whenever possible to avoid relative-URL edge cases.
- Reject leading ':' in user-supplied relative paths.
When it happens
Trigger: httpx.URL(':foo'), httpx.URL(path=':bar'), or constructing a relative reference where the path begins with a colon.
Common situations: Building a relative URL that accidentally begins with ':' (e.g. from a templated value); user input starting with ':'; mis-formed link extraction.
Related errors
- Relative URLs cannot have a path starting with '//'
- For absolute URLs, path must be empty or begin with '/'
- 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/ab88abf46eb943a4.json.
Report an issue: GitHub.