aio-libs/aiohttp · error · ValueError

Reader did not read all the data or it is malformed

Error message

Reader did not read all the data or it is malformed

What it means

ValueError raised by BodyPartReader.read_chunk when, after a part reaches EOF, the expected trailing CRLF separator after the part body is not present. This means the multipart framing is malformed — extra/missing bytes around the boundary.

Source

Thrown at aiohttp/multipart.py:395

                if self._prev_chunk:
                    over_chunk = self._prev_chunk[:over_chunk_size]
                    self._prev_chunk = self._prev_chunk[len(over_chunk) :]

                if len(over_chunk) != over_chunk_size:
                    over_chunk += await self._content.read(4 - len(over_chunk))

                if not over_chunk:
                    self._at_eof = True

                stripped_chunk += b"".join(over_chunk.split())
                chunk += over_chunk
                remainder = len(stripped_chunk) % 4

        self._read_bytes += len(chunk)
        if self._read_bytes == self._length:
            self._at_eof = True
        if self._at_eof and await self._content.readline() != b"\r\n":
            raise ValueError("Reader did not read all the data or it is malformed")
        return chunk

    async def _read_chunk_from_length(self, size: int) -> bytes:
        # Reads body part content chunk of the specified size.
        # The body part must has Content-Length header with proper value.
        assert self._length is not None, "Content-Length required for chunked read"
        chunk_size = min(size, self._length - self._read_bytes)
        chunk = await self._content.read(chunk_size)
        if self._content.at_eof():
            self._at_eof = True
        return chunk

    async def _read_chunk_from_stream(self, size: int) -> bytes:
        # Reads content chunk of body part with unknown length.
        # The Content-Length header for body part is not necessary.
        assert (
            size >= self._boundary_len
        ), "Chunk size must be greater or equal than boundary length + 2"

View on GitHub (pinned to c0ef574e29)

Solutions

  1. Verify the multipart boundary matches the Content-Type boundary parameter exactly.
  2. Check that each part is followed by \r\n before the boundary.
  3. Ensure Content-Length per part matches the actual body size.
  4. Regenerate the payload from a known-good encoder.
Defensive patterns

Strategy: try-catch

Try / catch

try:
    async for part in reader:
        data = await part.read()
except ValueError:
    return web.Response(status=400, text='malformed multipart')

Prevention

When it happens

Trigger: After reading the part body to EOF (read_bytes == length or stream EOF), read_chunk reads the next line and expects b'\r\n'; if it differs (missing CRLF, extra data, boundary mismatch), ValueError is raised.

Common situations: Malformed multipart body (missing CRLF between part and boundary); wrong/duplicate boundary; a part whose Content-Length is wrong so framing desynchronises; hand-crafted multipart with bad separators.

Related errors


AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04). Data as JSON: /data/errors/ec50413820657ea7.json. Report an issue: GitHub.