{"id":"d2db72028205eacd","repo":"encode/httpx","slug":"unexpected-type-for-content-type-content-r","errorCode":null,"errorMessage":"Unexpected type for 'content', {type(content)!r}","messagePattern":"Unexpected type for 'content', (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"httpx/_content.py","lineNumber":133,"sourceCode":"\n    elif isinstance(content, Iterable) and not isinstance(content, dict):\n        # `not isinstance(content, dict)` is a bit oddly specific, but it\n        # catches a case that's easy for users to make in error, and would\n        # otherwise pass through here, like any other bytes-iterable,\n        # because `dict` happens to be iterable. See issue #2491.\n        content_length_or_none = peek_filelike_length(content)\n\n        if content_length_or_none is None:\n            headers = {\"Transfer-Encoding\": \"chunked\"}\n        else:\n            headers = {\"Content-Length\": str(content_length_or_none)}\n        return headers, IteratorByteStream(content)  # type: ignore\n\n    elif isinstance(content, AsyncIterable):\n        headers = {\"Transfer-Encoding\": \"chunked\"}\n        return headers, AsyncIteratorByteStream(content)\n\n    raise TypeError(f\"Unexpected type for 'content', {type(content)!r}\")\n\n\ndef encode_urlencoded_data(\n    data: RequestData,\n) -> tuple[dict[str, str], ByteStream]:\n    plain_data = []\n    for key, value in data.items():\n        if isinstance(value, (list, tuple)):\n            plain_data.extend([(key, primitive_value_to_str(item)) for item in value])\n        else:\n            plain_data.append((key, primitive_value_to_str(value)))\n    body = urlencode(plain_data, doseq=True).encode(\"utf-8\")\n    content_length = str(len(body))\n    content_type = \"application/x-www-form-urlencoded\"\n    headers = {\"Content-Length\": content_length, \"Content-Type\": content_type}\n    return headers, ByteStream(body)\n\n","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/encode/httpx/blob/b5addb64f0161ff6bfe94c124ef76f6a1fba5254/httpx/_content.py#L115-L151","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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())."],"exampleFix":"// before\nclient.post(url, content={'key': 'val'})  # TypeError\n// after\nclient.post(url, json={'key': 'val'})\n// or\nclient.post(url, content=json.dumps({'key':'val'}).encode())","handlingStrategy":"type-guard","validationCode":"def normalize_content(content):\n    if isinstance(content, (bytes, str)):\n        return content\n    if isinstance(content, dict):\n        raise TypeError('dict content should use json= instead of content=')\n    if isinstance(content, (list, tuple)):\n        return [c.encode() if isinstance(c, str) else c for c in content]\n    raise TypeError(f'content must be str/bytes/iterable-of-bytes, got {type(content)!r}')","typeGuard":"import collections.abc as cabc\n\ndef is_valid_content(content) -> bool:\n    if isinstance(content, (bytes, str)):\n        return True\n    if isinstance(content, dict):\n        return False\n    if isinstance(content, cabc.Iterable):\n        return all(isinstance(x, bytes) for x in content)\n    return False","tryCatchPattern":"try:\n    resp = client.post(url, content=payload)\nexcept TypeError as exc:\n    if 'Unexpected type' in str(exc):\n        resp = client.post(url, json=payload)\n    else:\n        raise","preventionTips":["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."],"tags":["content","type-checking","request-body","validation"],"analyzedSha":"b5addb64f0161ff6bfe94c124ef76f6a1fba5254","analyzedAt":"2026-08-04T19:32:56.768Z","schemaVersion":2}