encode/httpx · error · ValueError
Proxy keys should use proper URL forms rather than plain sch
Error message
Proxy keys should use proper URL forms rather than plain scheme strings. Instead of "{pattern}", use "{pattern}://" What it means
httpx.URLPattern (used to match proxies and mounts) requires a proper URL-shaped pattern string. The constructor at httpx/_utils.py:165 checks if the pattern is non-empty and contains no ':' character; if so it raises ValueError telling you to turn a bare scheme like 'http' into a URL form like 'http://'. The validator exists because plain scheme strings would otherwise parse ambiguously or match nothing useful.
Source
Thrown at httpx/_utils.py:166
True
>>> pattern.matches(httpx.URL("http://example.com"))
True
>>> pattern.matches(httpx.URL("https://other.com"))
False
# With port matching...
>>> pattern = URLPattern("https://example.com:1234")
>>> pattern.matches(httpx.URL("https://example.com:1234"))
True
>>> pattern.matches(httpx.URL("https://example.com"))
False
"""
def __init__(self, pattern: str) -> None:
from ._urls import URL
if pattern and ":" not in pattern:
raise ValueError(
f"Proxy keys should use proper URL forms rather "
f"than plain scheme strings. "
f'Instead of "{pattern}", use "{pattern}://"'
)
url = URL(pattern)
self.pattern = pattern
self.scheme = "" if url.scheme == "all" else url.scheme
self.host = "" if url.host == "*" else url.host
self.port = url.port
if not url.host or url.host == "*":
self.host_regex: typing.Pattern[str] | None = None
elif url.host.startswith("*."):
# *.example.com should match "www.example.com", but not "example.com"
domain = re.escape(url.host[2:])
self.host_regex = re.compile(f"^.+\\.{domain}$")
elif url.host.startswith("*"):
# *example.com should match "www.example.com" and "example.com"View on GitHub (pinned to b5addb64f0)
Solutions
- Suffix the bare scheme with '://': use 'http://', 'https://', or the wildcard 'all://' as the pattern/mount key.
- For env-driven config, normalize at the boundary: pattern = scheme if '://' in scheme or ':' in scheme else scheme + '://'.
- If passing a full URL pattern (e.g. 'https://example.com'), it already contains ':' and passes; only bare scheme strings fail.
- Double-check mounts/proxy dict keys when porting requests proxies={'http': ...} to httpx mounts={'http://': ...}; the key format changed.
Example fix
// before
client = httpx.Client(mounts={
'http': httpx.HTTPTransport(proxy='http://proxy:8080'), # raises ValueError
})
// after
client = httpx.Client(mounts={
'http://': httpx.HTTPTransport(proxy='http://proxy:8080'),
}) Defensive patterns
Strategy: validation
Validate before calling
def normalize_proxy_key(pattern: str) -> str:
"""Ensure a proxy/mount key is a proper URL-shaped pattern.
'http' -> 'http://', 'all' -> 'all://', full URLs and wildcard
hosts pass through unchanged.
"""
if not pattern:
return pattern
if ':' in pattern:
return pattern
return f'{pattern}://'
# Usage at the config boundary:
raw = {'http': transport, 'all': transport}
mounts = {normalize_proxy_key(k): v for k, v in raw.items()} Type guard
def is_valid_urlpattern(pattern: str) -> bool:
"""True if pattern won't trip httpx.URLPattern's bare-scheme guard.
Empty patterns are allowed by httpx; non-empty must contain ':'.
"""
return pattern == '' or ':' in pattern Try / catch
import httpx
def build_pattern(pattern: str) -> httpx.URLPattern:
try:
return httpx.URLPattern(pattern)
except ValueError:
# Bare scheme: retry with the URL form recommended by the error.
if pattern and ':' not in pattern:
return httpx.URLPattern(f'{pattern}://')
raise Prevention
- When porting requests proxies={'http': ...} to httpx, always rewrite keys to 'http://' / 'https://' / 'all://'.
- Normalize scheme strings read from env/config at the trust boundary with the normalize_proxy_key helper above.
- Keep proxy/mount keys in a single constants module so the '://' suffix can't be forgotten per call site.
- Add a startup assert that every key in your mounts/proxies dict passes is_valid_urlpattern, so misconfigurations fail fast at boot, not at first request.
When it happens
Trigger: Constructing httpx.URLPattern('http'), httpx.URLPattern('https'), or any non-empty string without a colon. Most commonly hit when configuring mounts/proxies with a dict whose keys are bare schemes: client = httpx.Client(mounts={'http': httpx.HTTPTransport(...)}) or Client(proxy=...) variants that route through URLPattern. The check fires before any URL parsing, so any colon-less non-empty pattern raises immediately.
Common situations: Configuring httpx proxies/mounts from examples that abbreviated the scheme, or from config files/env vars that store just 'http'/'https'/'all'. Migrating from requests-style proxies={'http': ...} (bare scheme keys are idiomatic there) to httpx mounts={'http://': ...}. Typos like 'httpto' or trailing tokens without '://'. Auto-generated patterns from a scheme list that forgot the '://' suffix.
Related errors
- Proxy protocol must be either 'http', 'https', 'socks5', or
- Unknown scheme for proxy URL {url!r}
- URL too long
- Invalid URL component '{key}'
- Invalid port: {port!r}
AI-assisted analysis of encode/httpx@b5addb64f0 (2026-08-04).
Data as JSON: /data/errors/f04ec0516abe299e.json.
Report an issue: GitHub.