{"record":{"id":"9a1938c9700e73c1","repo":"aio-libs/aiohttp","slug":"unable-to-decode","errorCode":null,"errorMessage":"Unable to decode.","messagePattern":"Unable to decode\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"aiohttp/multipart.py","lineNumber":652,"sourceCode":"@payload_type(BodyPartReader, order=Order.try_first)\nclass BodyPartReaderPayload(Payload):\n    _value: BodyPartReader\n    # _autoclose = False (inherited) - Streaming reader that may have resources\n\n    def __init__(self, value: BodyPartReader, *args: Any, **kwargs: Any) -> None:\n        super().__init__(value, *args, **kwargs)\n\n        params: dict[str, str] = {}\n        if value.name is not None:\n            params[\"name\"] = value.name\n        if value.filename is not None:\n            params[\"filename\"] = value.filename\n\n        if params:\n            self.set_content_disposition(\"attachment\", True, **params)\n\n    def decode(self, encoding: str = \"utf-8\", errors: str = \"strict\") -> str:\n        raise TypeError(\"Unable to decode.\")\n\n    async def as_bytes(self, encoding: str = \"utf-8\", errors: str = \"strict\") -> bytes:\n        \"\"\"Raises TypeError as body parts should be consumed via write().\n\n        This is intentional: BodyPartReader payloads are designed for streaming\n        large data (potentially gigabytes) and must be consumed only once via\n        the write() method to avoid memory exhaustion. They cannot be buffered\n        in memory for reuse.\n        \"\"\"\n        raise TypeError(\"Unable to read body part as bytes. Use write() to consume.\")\n\n    async def write(self, writer: AbstractStreamWriter) -> None:\n        field = self._value\n        # Reading the part drains the underlying stream irreversibly, so mark the\n        # payload consumed up front: even an interrupted write leaves nothing that\n        # a retry or redirect could replay.\n        self._consumed = True\n        while chunk := await field.read_chunk(size=DEFAULT_CHUNK_SIZE):","sourceCodeStart":634,"sourceCodeEnd":670,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/multipart.py#L634-L670","documentation":"BodyPartReaderPayload.decode() unconditionally raises TypeError. This payload type wraps a streaming BodyPartReader and cannot be materialized into a str because it would force buffering arbitrarily large part bodies into memory.","triggerScenarios":"Calling .decode() on a payload obtained from MultipartReader.next() (a BodyPartReader wrapped in BodyPartReaderPayload), e.g. when passing the payload to an API that calls .decode() internally.","commonSituations":"Using a multipart part payload where a buffered bytes/str payload is expected; piping a BodyPartReaderPayload into helpers that materialize content via decode().","solutions":["Consume the part via the streaming API: async for chunk in part: ... or await part.write(writer).","If you truly need a string, read all chunks manually then decode once: data = b''.join([c async for c in part]); data.decode().","Do not pass BodyPartReaderPayload to APIs that call decode()/as_bytes(); pass a BytesPayload instead."],"exampleFix":"// before\npayload = BodyPartReaderPayload(part)\ntext = payload.decode()\n\n// after\nchunks = []\nasync for chunk in part:\n    chunks.append(chunk)\ntext = b''.join(chunks).decode('utf-8')","handlingStrategy":"type-guard","validationCode":"from aiohttp.multipart import BodyPartReaderPayload, Payload\n\ndef materialize_text(payload) -> str:\n    if isinstance(payload, BodyPartReaderPayload):\n        raise TypeError('Use write() to stream BodyPartReaderPayload, not decode()')\n    return payload.decode()","typeGuard":"from aiohttp.multipart import BodyPartReaderPayload\n\ndef is_streaming_payload(p: object) -> bool:\n    return isinstance(p, BodyPartReaderPayload)","tryCatchPattern":"try:\n    text = payload.decode()\nexcept TypeError as e:\n    if 'Unable to decode' in str(e):\n        # drain the streaming part manually\n        chunks = []\n        async for c in payload._value:\n            chunks.append(c)\n        text = b''.join(chunks).decode('utf-8')\n    else:\n        raise","preventionTips":["Never call .decode() on a BodyPartReaderPayload; consume it via write() or read_chunk().","Type-check payloads before passing them to generic serializers that call decode().","If you need a string from a streaming part, drain chunks yourself and decode once."],"tags":["multipart","payload","streaming","typeerror","api-misuse"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}