aio-libs/aiohttp · error · TypeError

Unable to read body part as bytes. Use write() to consume.

Error message

Unable to read body part as bytes. Use write() to consume.

What it means

BodyPartReaderPayload.as_bytes() unconditionally raises TypeError. Because the underlying BodyPartReader streams potentially gigabytes and can only be consumed once, buffering it into bytes would risk memory exhaustion and break single-consumption semantics.

Solutions

  1. Use await payload.write(writer) to stream the part to a file/response/IO writer.
  2. If you must have bytes and the part is known small, drain it manually: buf = io.BytesIO(); writer = StreamResponse(...); await payload.write(BytesWriter(buf)).
  3. Replace the BodyPartReaderPayload with a BytesPayload built from explicitly read bytes when buffering is acceptable.

Example fix

// before
data = await payload.as_bytes()

// after
buf = io.BytesIO()
class W(AbstractStreamWriter):
    async def write(self, chunk): buf.write(chunk)
await payload.write(W())
data = buf.getvalue()
Defensive patterns

Strategy: type-guard

Validate before calling

from aiohttp.multipart import BodyPartReaderPayload

async def to_bytes(payload) -> bytes:
    if isinstance(payload, BodyPartReaderPayload):
        buf = bytearray()
        class W(AbstractStreamWriter):
            async def write(self, chunk): buf.extend(chunk)
            async def write_headers(self, *a, **k): ...
            async def write_eof(self, *a, **k): ...
        await payload.write(W())
        return bytes(buf)
    return await payload.as_bytes()

Type guard

from aiohttp.multipart import BodyPartReaderPayload

def is_streaming_payload(p: object) -> bool:
    return isinstance(p, BodyPartReaderPayload)

Try / catch

try:
    data = await payload.as_bytes()
except TypeError as e:
    if 'Use write()' in str(e):
        data = await stream_to_bytes(payload)
    else:
        raise

Prevention

When it happens

Trigger: Calling await payload.as_bytes() on a BodyPartReaderPayload, or handing such a payload to code that calls as_bytes() (e.g. some serializer or test helper).

Common situations: Treating a streaming multipart part like an in-memory payload; test code that calls as_bytes() to assert on content; frameworks that auto-buffer payloads.

Related errors


AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11). Data as JSON: /api/errors/a6e2d66a0a2f299f. Report an issue: GitHub.

Appendix: source

Thrown at aiohttp/multipart.py:662

            params["name"] = value.name
        if value.filename is not None:
            params["filename"] = value.filename

        if params:
            self.set_content_disposition("attachment", True, **params)

    def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str:
        raise TypeError("Unable to decode.")

    async def as_bytes(self, encoding: str = "utf-8", errors: str = "strict") -> bytes:
        """Raises TypeError as body parts should be consumed via write().

        This is intentional: BodyPartReader payloads are designed for streaming
        large data (potentially gigabytes) and must be consumed only once via
        the write() method to avoid memory exhaustion. They cannot be buffered
        in memory for reuse.
        """
        raise TypeError("Unable to read body part as bytes. Use write() to consume.")

    async def write(self, writer: AbstractStreamWriter) -> None:
        field = self._value
        # Reading the part drains the underlying stream irreversibly, so mark the
        # payload consumed up front: even an interrupted write leaves nothing that
        # a retry or redirect could replay.
        self._consumed = True
        while chunk := await field.read_chunk(size=DEFAULT_CHUNK_SIZE):
            async for d in field.decode_iter(chunk):
                await writer.write(d)


class MultipartReader:
    """Multipart body reader."""

    #: Response wrapper, used when multipart readers constructs from response.
    response_wrapper_cls = MultipartResponseWrapper
    #: Multipart reader class, used to handle multipart/* body parts.

View on GitHub (pinned to d041d4d0fd)