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
- Verify the multipart boundary matches the Content-Type boundary parameter exactly.
- Check that each part is followed by \r\n before the boundary.
- Ensure Content-Length per part matches the actual body size.
- 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
- Use a standards-compliant multipart encoder.
- Keep per-part Content-Length accurate.
- Validate the boundary string matches.
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
- Reading after EOF
- invalid Content-Length: {length!r}
- boundary missed for Content-Type: %s
- boundary %r is too long (70 chars max)
- Could not find starting boundary {self._boundary!r}
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/ec50413820657ea7.json.
Report an issue: GitHub.