{"id":"177be9342c2a4411","repo":"aio-libs/aiohttp","slug":"unsupported-body-type-r","errorCode":null,"errorMessage":"Unsupported body type %r","messagePattern":"Unsupported body type %r","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/web_response.py","lineNumber":620,"sourceCode":"\n        self._zlib_executor_size = zlib_executor_size\n        self._zlib_executor = zlib_executor\n\n    @property\n    def body(self) -> bytes | bytearray | Payload | None:\n        return self._body\n\n    @body.setter\n    def body(self, body: Any) -> None:\n        if body is None:\n            self._body = None\n        elif isinstance(body, (bytes, bytearray)):\n            self._body = body\n        else:\n            try:\n                self._body = body = payload.PAYLOAD_REGISTRY.get(body)\n            except payload.LookupError:\n                raise ValueError(\"Unsupported body type %r\" % type(body))\n\n            headers = self._headers\n\n            # set content-type\n            if hdrs.CONTENT_TYPE not in headers:\n                headers[hdrs.CONTENT_TYPE] = body.content_type\n\n            # copy payload headers\n            if body.headers:\n                for key, value in body.headers.items():\n                    if key not in headers:\n                        headers[key] = value\n\n        self._compressed_body = None\n\n    @property\n    def text(self) -> str | None:\n        if self._body is None:","sourceCodeStart":602,"sourceCodeEnd":638,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/web_response.py#L602-L638","documentation":"The body setter tries to coerce non-bytes values via payload.PAYLOAD_REGISTRY.get (line 618). If no registered Payload type matches the object, it raises ValueError listing the unsupported type. Only bytes/bytearray pass directly; everything else needs a registered payload type (e.g. str, dict via aiohttp payload types).","triggerScenarios":"Assigning resp.body = some_custom_object that has no registered Payload; passing an int, list, or arbitrary class instance; resp.body = a generator (not a registered payload stream type).","commonSituations":"Setting body to an object that isn't bytes and has no registered aiohttp payload serializer; forgetting that Response(text=...) handles str while body= does not.","solutions":["Encode to bytes first: resp.body = str(obj).encode() or json.dumps(obj).encode().","For str use text=, for JSON use json_response(data=...).","Register a custom Payload type via payload.PAYLOAD_REGISTRY.register if you need first-class support."],"exampleFix":"# before\nresp = Response()\nresp.body = {'key': 'value'}  # dict has no payload by default -> ValueError\n\n# after\nfrom aiohttp import json_response\nresp = json_response({'key': 'value'})","handlingStrategy":"type-guard","validationCode":"def coerce_body(value):\n    if isinstance(value, (bytes, bytearray)):\n        return value\n    if isinstance(value, str):\n        return value.encode()\n    raise TypeError(f'Use json_response/text= for {type(value)}; body= needs bytes')","typeGuard":"def is_bytes_body(value) -> bool:\n    return isinstance(value, (bytes, bytearray))","tryCatchPattern":null,"preventionTips":["Encode str/dict/list to bytes before assigning to body.","Use Response(text=...) for str and json_response(data=...) for objects.","Register a custom Payload type only if you need reusable first-class support."],"tags":["http","response","body","payload","type-check"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}