{"record":{"id":"ec50413820657ea7","repo":"aio-libs/aiohttp","slug":"reader-did-not-read-all-the-data-or-it-is-malforme","errorCode":null,"errorMessage":"Reader did not read all the data or it is malformed","messagePattern":"Reader did not read all the data or it is malformed","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/multipart.py","lineNumber":395,"sourceCode":"                if self._prev_chunk:\n                    over_chunk = self._prev_chunk[:over_chunk_size]\n                    self._prev_chunk = self._prev_chunk[len(over_chunk) :]\n\n                if len(over_chunk) != over_chunk_size:\n                    over_chunk += await self._content.read(4 - len(over_chunk))\n\n                if not over_chunk:\n                    self._at_eof = True\n\n                stripped_chunk += b\"\".join(over_chunk.split())\n                chunk += over_chunk\n                remainder = len(stripped_chunk) % 4\n\n        self._read_bytes += len(chunk)\n        if self._read_bytes == self._length:\n            self._at_eof = True\n        if self._at_eof and await self._content.readline() != b\"\\r\\n\":\n            raise ValueError(\"Reader did not read all the data or it is malformed\")\n        return chunk\n\n    async def _read_chunk_from_length(self, size: int) -> bytes:\n        # Reads body part content chunk of the specified size.\n        # The body part must has Content-Length header with proper value.\n        assert self._length is not None, \"Content-Length required for chunked read\"\n        chunk_size = min(size, self._length - self._read_bytes)\n        chunk = await self._content.read(chunk_size)\n        if self._content.at_eof():\n            self._at_eof = True\n        return chunk\n\n    async def _read_chunk_from_stream(self, size: int) -> bytes:\n        # Reads content chunk of body part with unknown length.\n        # The Content-Length header for body part is not necessary.\n        assert (\n            size >= self._boundary_len\n        ), \"Chunk size must be greater or equal than boundary length + 2\"","sourceCodeStart":377,"sourceCodeEnd":413,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/multipart.py#L377-L413","documentation":"Raised at end-of-stream when the body part's trailing CRLF is missing or wrong. After reading exactly _length bytes, BodyPartReader expects the next two bytes read via readline() to equal b'\\r\\n'; anything else means the declared Content-Length did not match the actual body, or the framing CRLF before the boundary is absent.","triggerScenarios":"A body part whose Content-Length under- or over-counts the real payload bytes, or a producer that omits the CRLF separating part body from the boundary line. Also triggered when the stream is truncated mid-part.","commonSituations":"Multipart generators that compute Content-Length from the undecoded size but the reader decodes base64/quoted-printable, or vice versa; truncated responses from a closing proxy; tests with hand-written multipart strings missing the trailing CRLF.","solutions":["Verify the producer writes exactly Content-Length bytes followed by '\\r\\n' before the next boundary.","If Content-Length is uncertain, emit the part without it and rely on boundary framing instead.","Re-encode transfer-encoding (base64/QP) consistently on both length computation and body bytes.","Catch ValueError at the call site of read_chunk()/read() to tolerate truncated streams and log the offending part."],"exampleFix":"// before\n--BOUNDARY\r\nContent-Length: 5\r\n\r\nhello--BOUNDARY--\r\n\n// after\n--BOUNDARY\r\nContent-Length: 5\r\n\r\nhello\r\n--BOUNDARY--\r\n","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    while not part.at_eof():\n        chunk = await part.read_chunk(8192)\nexcept ValueError as e:\n    # part body did not match Content-Length or lacked trailing CRLF\n    log.warning('Malformed body part %s: %s', part.name, e)\n    raise web.HTTPBadRequest(text='Malformed multipart body')","preventionTips":["When generating multipart, write exactly Content-Length bytes then a CRLF before the boundary.","Compute Content-Length from the same bytes you actually write (post transfer-encoding).","Treat read failures as fatal framing errors; do not attempt partial processing."],"tags":["multipart","content-length","framing","stream-integrity"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}