encode/httpx · error · TypeError
Argument {key!r} must be {expected} but got {seen}
Error message
Argument {key!r} must be {expected} but got {seen} What it means
Raised by URL.__init__ when a kwarg key IS in the allowed set but the value's type does not match the declared type (e.g. port must be int, scheme/path must be str, userinfo/query/raw_path/netloc must be bytes). The check skips None. Message names the expected type and the actually-seen type.
Source
Thrown at httpx/_urls.py:103
"port": int,
"netloc": bytes,
"path": str,
"query": bytes,
"raw_path": bytes,
"fragment": str,
"params": object,
}
# Perform type checking for all supported keyword arguments.
for key, value in kwargs.items():
if key not in allowed:
message = f"{key!r} is an invalid keyword argument for URL()"
raise TypeError(message)
if value is not None and not isinstance(value, allowed[key]):
expected = allowed[key].__name__
seen = type(value).__name__
message = f"Argument {key!r} must be {expected} but got {seen}"
raise TypeError(message)
if isinstance(value, bytes):
kwargs[key] = value.decode("ascii")
if "params" in kwargs:
# Replace any "params" keyword with the raw "query" instead.
#
# Ensure that empty params use `kwargs["query"] = None` rather
# than `kwargs["query"] = ""`, so that generated URLs do not
# include an empty trailing "?".
params = kwargs.pop("params")
kwargs["query"] = None if not params else str(QueryParams(params))
if isinstance(url, str):
self._uri_reference = urlparse(url, **kwargs)
elif isinstance(url, URL):
self._uri_reference = url._uri_reference.copy_with(**kwargs)
else:
raise TypeError(View on GitHub (pinned to b5addb64f0)
Solutions
- Match the documented types: str for scheme/username/password/host/path/fragment; int for port; bytes for userinfo/query/raw_path/netloc.
- Decode bytes to str (or encode str to bytes) explicitly before passing.
- Use the convenience aliases (username/password/netloc/raw_path/params) which httpx converts for you.
- Add a typed wrapper or dataclass that guarantees types reach URL().
Example fix
// before url = httpx.URL(scheme=b"https", host="example.com") # TypeError: scheme must be str // after url = httpx.URL(scheme="https", host="example.com")
Defensive patterns
Strategy: type-guard
Validate before calling
URL_KWARG_TYPES = {
"scheme": str, "username": str, "password": str, "userinfo": bytes,
"host": str, "port": int, "netloc": bytes, "path": str,
"query": bytes, "raw_path": bytes, "fragment": str, "params": object,
}
def coerce_url_kwargs(kwargs: dict) -> dict:
out = {}
for k, v in kwargs.items():
if v is None:
out[k] = v
continue
expected = URL_KWARG_TYPES[k]
if not isinstance(v, expected):
if expected is str and isinstance(v, bytes):
v = v.decode("ascii")
elif expected is bytes and isinstance(v, str):
v = v.encode("ascii")
elif expected is int:
v = int(v)
else:
raise TypeError(f"{k!r} must be {expected.__name__}")
out[k] = v
return out Type guard
def url_kwargs_match_types(kwargs: dict) -> bool:
types = {
"scheme": str, "username": str, "password": str, "userinfo": bytes,
"host": str, "port": int, "netloc": bytes, "path": str,
"query": bytes, "raw_path": bytes, "fragment": str, "params": object,
}
return all(
v is None or isinstance(v, types[k])
for k, v in kwargs.items() if k in types
) Try / catch
try:
url = httpx.URL(base, **kwargs)
except TypeError as e:
if "must be" in str(e) and "but got" in str(e):
raise TypeError(f"URL kwarg type mismatch: {e}") from e
raise Prevention
- Memorize the bytes-vs-str split: userinfo/query/raw_path/netloc are bytes.
- Decode/encode at the boundary so the right type reaches URL().
- Add a thin typed wrapper around URL construction in shared code.
When it happens
Trigger: httpx.URL(port='8080') is fine (port is special-cased), but httpx.URL(scheme=b'https') (bytes for a str field), httpx.URL(host=123), httpx.URL(path=b'/x'), or httpx.URL(query='/x') (str for bytes field) raise.
Common situations: Passing bytes to a str-typed field after reading from a binary source; passing an int host; mixing up which fields are bytes (userinfo, query, raw_path, netloc) vs str (scheme, username, password, host, path, fragment).
Related errors
- Invalid type for url. Expected str or httpx.URL, got {type(
- {key!r} is an invalid keyword argument for URL()
- 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/8730261d131b2118.json.
Report an issue: GitHub.