{"record":{"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":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/multipart.py","lineNumber":883,"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":865,"sourceCodeEnd":901,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/multipart.py#L865-L901","documentation":"In _read_boundary, the line read between parts must equal either the boundary or the closing boundary ('--BOUNDARY--'). If it matches neither (and is not a recoverable epilogue/parent-boundary case), ValueError is raised showing the actual vs expected boundary.","triggerScenarios":"A boundary line that differs from the one declared in Content-Type; mid-stream corruption; nested multipart where the inner boundary collides with or differs from the outer; a producer that changes boundary tokens between parts.","commonSituations":"Mismatched boundary strings between client and server; proxies rewriting the body but not the Content-Type boundary; truncated or interleaved multipart; attacks injecting fake boundaries.","solutions":["Confirm the boundary token in the body exactly matches the Content-Type boundary parameter (including dashes and case).","Ensure nested multipart uses distinct boundaries that do not collide.","Do not let proxies rewrite multipart bodies piecemeal.","Catch ValueError and abort with 400; optionally log chunk vs boundary to diagnose corruption."],"exampleFix":"// before\nContent-Type: multipart/form-data; boundary=----A\r\n...------B\r\n\n// after\nContent-Type: multipart/form-data; boundary=----A\r\n...------A\r\n","handlingStrategy":"try-catch","validationCode":"from aiohttp.multipart import parse_mimetype\n\ndef boundary_matches_header(content_type: str, body_first_line: bytes) -> bool:\n    mt = parse_mimetype(content_type)\n    expected = b'--' + mt.parameters.get('boundary', '').encode()\n    return body_first_line.rstrip(b'\\r\\n') == expected","typeGuard":null,"tryCatchPattern":"try:\n    async for part in reader:\n        process(part)\nexcept ValueError as e:\n    if 'Invalid boundary' in str(e):\n        return web.Response(status=400, text='Boundary mismatch in multipart body')\n    raise","preventionTips":["Keep the boundary token identical in Content-Type and in every body line.","Use distinct boundaries for nested multipart to avoid collisions.","Do not let proxies rewrite multipart bodies without adjusting Content-Type."],"tags":["multipart","boundary","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"}