{"id":"c54332184ce8e026","repo":"aio-libs/aiohttp","slug":"invalid-boundary-chunk-r-expected-self-bounda","errorCode":null,"errorMessage":"Invalid boundary {chunk!r}, expected {self._boundary!r}","messagePattern":"Invalid boundary (.+?), expected (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/multipart.py","lineNumber":879,"sourceCode":"            pass\n        elif chunk == self._boundary + b\"--\":\n            self._at_eof = True\n            epilogue = await self._readline()\n            next_line = await self._readline()\n\n            # the epilogue is expected and then either the end of input or the\n            # parent multipart boundary, if the parent boundary is found then\n            # it should be marked as unread and handed to the parent for\n            # processing\n            if next_line[:2] == b\"--\":\n                self._unread.append(next_line)\n            # otherwise the request is likely missing an epilogue and both\n            # lines should be passed to the parent for processing\n            # (this handles the old behavior gracefully)\n            else:\n                self._unread.extend([next_line, epilogue])\n        else:\n            raise ValueError(f\"Invalid boundary {chunk!r}, expected {self._boundary!r}\")\n\n    async def _read_headers(self) -> HeadersDictProxy:\n        lines = []\n        while True:\n            chunk = await self._content.readline(max_line_length=self._max_field_size)\n            chunk = chunk.rstrip(b\"\\r\\n\")\n            lines.append(chunk)\n            if not chunk:\n                break\n            if len(lines) > self._max_headers:\n                raise BadHttpMessage(\"Too many headers received\")\n        parser = HeadersParser(max_field_size=self._max_field_size)\n        headers, _ = parser.parse_headers(lines)\n        return headers\n\n    async def _maybe_release_last_part(self) -> None:\n        \"\"\"Ensures that the last read body part is read completely.\"\"\"\n        if self._last_part is not None:","sourceCodeStart":861,"sourceCodeEnd":897,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/multipart.py#L861-L897","documentation":"Raised by MultipartReader._read_boundary() when, after the first part, the reader reads a delimiter line that is neither the expected `--<boundary>` (start of next part) nor `--<boundary>--` (final delimiter). This indicates the stream is corrupted or the boundary has drifted out of sync.","triggerScenarios":"Iterating parts with `await reader.next()` and the bytes between parts do not match the configured boundary. Caused by a body whose internal delimiters differ from the Content-Type boundary, or by part bodies that leaked across the boundary due to a wrong Content-Length.","commonSituations":"Mismatched boundary between Content-Type and body; a part with an incorrect Content-Length causing the reader to start mid-part; nested multipart with wrong reader; man-in-the-middle corruption.","solutions":["Confirm the Content-Type boundary exactly equals the delimiters inside the body.","Ensure upstream sets correct Content-Length on each part or uses chunked framing consistently.","Catch ValueError and abort the multipart parse with a 400/502."],"exampleFix":"// before\nasync for part in reader:  # mid-body delimiter mismatch -> ValueError\n    ...\n// after\ntry:\n    async for part in reader:\n        ...\nexcept ValueError as e:\n    return web.Response(status=400, text=f'malformed multipart: {e}')\n","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    async for part in reader:\n        handle(part)\nexcept ValueError as e:\n    if 'Invalid boundary' in str(e):\n        return web.Response(status=400, text='multipart stream corrupted')\n    raise","preventionTips":["Ensure each part has a correct Content-Length so boundaries stay aligned.","Do not manually edit a multipart body without re-deriving boundaries.","Treat mid-stream boundary mismatch as unrecoverable corruption."],"tags":["multipart","boundary","protocol","corruption"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}