encode/httpx · error · TypeError
Unexpected type for 'content', {type(content)!r}
Error message
Unexpected type for 'content', {type(content)!r} What it means
This TypeError is the terminal fallthrough of httpx._content.encode_content. The function accepts str, bytes, an Iterable[bytes] (non-dict), or an AsyncIterable[bytes]; anything else reaching line 133 is rejected. The dict-specific guard a few lines up exists because dict is iterable but almost always a caller mistake (issue #2491).
Source
Thrown at httpx/_content.py:133
elif isinstance(content, Iterable) and not isinstance(content, dict):
# `not isinstance(content, dict)` is a bit oddly specific, but it
# catches a case that's easy for users to make in error, and would
# otherwise pass through here, like any other bytes-iterable,
# because `dict` happens to be iterable. See issue #2491.
content_length_or_none = peek_filelike_length(content)
if content_length_or_none is None:
headers = {"Transfer-Encoding": "chunked"}
else:
headers = {"Content-Length": str(content_length_or_none)}
return headers, IteratorByteStream(content) # type: ignore
elif isinstance(content, AsyncIterable):
headers = {"Transfer-Encoding": "chunked"}
return headers, AsyncIteratorByteStream(content)
raise TypeError(f"Unexpected type for 'content', {type(content)!r}")
def encode_urlencoded_data(
data: RequestData,
) -> tuple[dict[str, str], ByteStream]:
plain_data = []
for key, value in data.items():
if isinstance(value, (list, tuple)):
plain_data.extend([(key, primitive_value_to_str(item)) for item in value])
else:
plain_data.append((key, primitive_value_to_str(value)))
body = urlencode(plain_data, doseq=True).encode("utf-8")
content_length = str(len(body))
content_type = "application/x-www-form-urlencoded"
headers = {"Content-Length": content_length, "Content-Type": content_type}
return headers, ByteStream(body)
View on GitHub (pinned to b5addb64f0)
Solutions
- Use json=<value> for dict/structured data instead of content=<dict>.
- Coerce to bytes before passing: content=str(value).encode() or content=bytes(value).
- For a list of strings, map to bytes: content=[s.encode() for s in items].
- If you have an arbitrary object, serialize it first (json.dumps(...).encode()).
Example fix
// before
client.post(url, content={'key': 'val'}) # TypeError
// after
client.post(url, json={'key': 'val'})
// or
client.post(url, content=json.dumps({'key':'val'}).encode()) Defensive patterns
Strategy: type-guard
Validate before calling
def normalize_content(content):
if isinstance(content, (bytes, str)):
return content
if isinstance(content, dict):
raise TypeError('dict content should use json= instead of content=')
if isinstance(content, (list, tuple)):
return [c.encode() if isinstance(c, str) else c for c in content]
raise TypeError(f'content must be str/bytes/iterable-of-bytes, got {type(content)!r}') Type guard
import collections.abc as cabc
def is_valid_content(content) -> bool:
if isinstance(content, (bytes, str)):
return True
if isinstance(content, dict):
return False
if isinstance(content, cabc.Iterable):
return all(isinstance(x, bytes) for x in content)
return False Try / catch
try:
resp = client.post(url, content=payload)
except TypeError as exc:
if 'Unexpected type' in str(exc):
resp = client.post(url, json=payload)
else:
raise Prevention
- Use json= for dicts and structured data, content= only for bytes/str.
- Coerce numeric/None values to bytes/str before passing.
- Wrap list-of-str content with .encode() on each element.
- Unit-test request construction with the exact payload types you use.
When it happens
Trigger: Passing content=<dict> with a dict that slipped past the guard (or a dict subclass); passing content=<int>/<float>/<None substitute>/custom object; calling Response(content=...) or Request(content=...) with a non-byte-iterable like a list of str; passing a non-iterable object such as a number.
Common situations: Passing content=some_dict instead of json=some_dict; passing content=123; passing content=["a","b"] (list of str, not bytes); passing content=None-equivalent or a numpy array / pandas object without conversion; mixing up content= and data= semantics.
Related errors
- Header value must be str or bytes, not {type(value)}
- Attempted to read or stream some content, but the content ha
- {key}
- Attempted to read or stream some content, but the content ha
- Invalid type for name. Expected str, got {type(name)}: {name
AI-assisted analysis of encode/httpx@b5addb64f0 (2026-08-04).
Data as JSON: /data/errors/d2db72028205eacd.json.
Report an issue: GitHub.