{"id":"4481695be120fc5a","repo":"aio-libs/aiohttp","slug":"too-many-headers-received-448169","errorCode":null,"errorMessage":"Too many headers received","messagePattern":"Too many headers received","errorType":"exception","errorClass":"BadHttpMessage","httpStatus":400,"severity":"error","filePath":"aiohttp/multipart.py","lineNumber":890,"sourceCode":"                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:\n            if not self._last_part.at_eof():\n                await self._last_part.release()\n            self._unread.extend(self._last_part._unread)\n            self._last_part = None\n\n\n_Part = tuple[Payload, str, str]\n\n\nclass MultipartWriter(Payload):\n    \"\"\"Multipart body writer.\"\"\"","sourceCodeStart":872,"sourceCodeEnd":908,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/multipart.py#L872-L908","documentation":"Raised by MultipartReader._read_headers() when a single multipart part contains more header lines than max_headers (default 128). This is a hard cap to prevent unbounded memory/CPU consumption from a part with a header bomb. It raises BadHttpMessage (an HTTP processing error), not a plain ValueError.","triggerScenarios":"Receiving a multipart part whose header block exceeds 128 lines (configurable via the MultipartReader max_headers kwarg). Triggered during fetch_next_part() while reading the next part's headers.","commonSituations":"Malicious clients sending header bombs; buggy generators emitting duplicate headers in a loop; legitimate use with a very large number of custom metadata headers exceeding the default.","solutions":["Reject the request as 400 Bad Request (this is an HTTP processing error).","If you legitimately need more headers per part, raise max_headers when constructing the reader: `MultipartReader(headers, content, max_headers=256)`.","Investigate the sender — >128 headers in one part is almost always a bug."],"exampleFix":"// before\nreader = await request.multipart()  # part with 200 headers -> BadHttpMessage\n// after\nreader = MultipartReader(\n    request.headers, request.content, max_headers=256\n)\n","handlingStrategy":"try-catch","validationCode":"from aiohttp.http_exceptions import BadHttpMessage\n# pre-check is impractical (headers not yet read); configure the cap explicitly:\nreader = MultipartReader(headers, content, max_headers=256)","typeGuard":null,"tryCatchPattern":"from aiohttp.http_exceptions import BadHttpMessage\ntry:\n    async for part in reader:\n        process(part)\nexcept BadHttpMessage as e:\n    if 'Too many headers' in str(e):\n        return web.Response(status=400, text='header limit exceeded')\n    raise","preventionTips":["Keep max_headers at a sane cap; raise it only with justification.","Reject parts exceeding the limit as 400 (DoS protection).","Monitor for clients that routinely approach the header cap."],"tags":["multipart","headers","limits","security","dos-protection"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}