{"id":"8c9d8667e471d70c","repo":"aio-libs/aiohttp","slug":"unable-to-decode-content-not-cached-call-as-byt","errorCode":null,"errorMessage":"Unable to decode - content not cached. Call as_bytes() first.","messagePattern":"Unable to decode - content not cached\\. Call as_bytes\\(\\) first\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"aiohttp/payload.py","lineNumber":1075,"sourceCode":"                    await writer.write(chunk)\n                # If we have a content length limit\n                elif remaining_bytes > 0:\n                    await writer.write(chunk[:remaining_bytes])\n                    remaining_bytes -= len(chunk)\n                # We still want to exhaust the iterator even\n                # if we have reached the content length limit\n                # since the file handle may not get closed by\n                # the iterator if we don't do this\n        except StopAsyncIteration:\n            # Iterator is exhausted\n            self._iter = None\n            self._consumed = True  # Mark as consumed when streamed without caching\n\n    def decode(self, encoding: str = \"utf-8\", errors: str = \"strict\") -> str:\n        \"\"\"Decode the payload content as a string if cached chunks are available.\"\"\"\n        if self._cached_chunks is not None:\n            return b\"\".join(self._cached_chunks).decode(encoding, errors)\n        raise TypeError(\"Unable to decode - content not cached. Call as_bytes() first.\")\n\n    async def as_bytes(self, encoding: str = \"utf-8\", errors: str = \"strict\") -> bytes:\n        \"\"\"\n        Return bytes representation of the value.\n\n        This method reads the entire async iterable content and returns it as bytes.\n        It generates and caches the chunks for future reuse.\n        \"\"\"\n        # If we have cached chunks, return them joined\n        if self._cached_chunks is not None:\n            return b\"\".join(self._cached_chunks)\n\n        # If iterator is exhausted and no cache, return empty\n        if self._iter is None:\n            return b\"\"\n\n        # Read all chunks and cache them\n        chunks: list[bytes] = []","sourceCodeStart":1057,"sourceCodeEnd":1093,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/payload.py#L1057-L1093","documentation":"Raised by AsyncIterablePayload.decode() when the payload has not yet been materialized into a cache. AsyncIterablePayload streams lazily and only populates _cached_chunks after as_bytes() runs; decode() is a synchronous helper that needs that cache to exist. Calling decode() on a fresh or write-only payload therefore fails. The fix is to call the async as_bytes() first, which populates the cache and makes decode() reusable.","triggerScenarios":"Calling payload.decode() directly on an AsyncIterablePayload (or StreamReaderPayload) that was streamed via write() without ever calling as_bytes(). Reproducible when a test or middleware tries to log the body as text after the payload was consumed by the writer.","commonSituations":"Debug logging that wants to peek at the body; tests that assert on payload content; middleware that reads body for inspection; using decode() (sync) instead of as_bytes() (async) on a streaming payload.","solutions":["Call `await payload.as_bytes()` first to populate the cache, then payload.decode() works.","If you only need the string, use `data = await payload.as_bytes(); text = data.decode('utf-8')` directly.","Avoid decode() for streaming payloads you intend to also send — materializing consumes the iterator.","Use BytesPayload instead if you need synchronous decode() support from the start."],"exampleFix":"// before\ntext = payload.decode('utf-8')  # raises TypeError\n// after\ndata = await payload.as_bytes()\ntext = data.decode('utf-8')","handlingStrategy":"validation","validationCode":"# Always materialize before sync decode:\nif payload._cached_chunks is None:\n    data = await payload.as_bytes()  # populates cache\ntext = payload.decode() if payload._cached_chunks is not None else data.decode()","typeGuard":null,"tryCatchPattern":"try:\n    text = payload.decode()\nexcept TypeError:\n    data = await payload.as_bytes()\n    text = data.decode('utf-8')","preventionTips":["Treat decode() as available only after as_bytes() for streaming payloads.","Prefer BytesPayload when you need synchronous decode().","Wrap decode() in a helper that falls back to as_bytes()."],"tags":["payload","streaming","state"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}