aio-libs/aiohttp · error · BadHttpMessage
Too many headers received
Error message
Too many headers received
What it means
Raised by HttpParser.feed_data (aiohttp/http_parser.py:384) when the number of accumulated lines (request/status line plus every header line) exceeds max_headers (default 128). This is a memory-exhaustion / DoS guard: it caps how many header lines a single message can carry before the parser refuses.
Source
Thrown at aiohttp/http_parser.py:384
continue
if pos >= start_pos:
if should_close:
raise BadHttpMessage("Data after `Connection: close`")
# line found
line = data[start_pos:pos]
if SEP == b"\n": # For lax response parsing
line = line.rstrip(b"\r")
if len(line) > max_line_length:
raise LineTooLong(line[:100] + b"...", max_line_length)
self._lines.append(line)
# After processing the status/request line, everything is a header.
max_line_length = self.max_field_size
if len(self._lines) > self.max_headers:
raise BadHttpMessage("Too many headers received")
start_pos = pos + len(SEP)
# \r\n\r\n found
if self._lines[-1] == EMPTY:
max_trailers = self.max_headers - len(self._lines)
try:
msg: _MsgT = self.parse_message(self._lines)
finally:
self._lines.clear()
def get_content_length() -> int | None:
# payload length
length_hdr = msg.headers.get(CONTENT_LENGTH)
if length_hdr is None:
return None
# Shouldn't allow +/- or other number formats.View on GitHub (pinned to c0ef574e29)
Solutions
- Raise max_headers (server: Application request-parser kwargs) for routes that legitimately need more.
- Reduce the number of headers your client sends; consolidate or drop redundant ones.
- On the server, the default 128 returns 400 - monitor and tune per route if needed; rate-limit clients that flood headers.
Example fix
# before - default max_headers (128) too low
app = web.Application()
# after - raise the cap for routes that need it
app = web.Application(handler_args={'max_headers': 256}) Defensive patterns
Strategy: validation
Validate before calling
MAX_OUTGOING_HEADERS = 128
def header_count_ok(headers) -> bool:
return len(headers) <= MAX_OUTGOING_HEADERS
if not header_count_ok(outgoing):
raise ValueError(f'too many headers ({len(outgoing)})') Try / catch
from aiohttp import http_exceptions
try:
await request.read()
except http_exceptions.BadHttpMessage as e:
if 'Too many headers' in str(e):
return web.Response(status=431) # Request Header Fields Too Large
raise Prevention
- Keep the number of headers well under 128
- Tune max_headers for routes that legitimately need more
- Rate-limit clients that send header floods
When it happens
Trigger: A request or response carrying more than 128 header lines (the count includes the leading request/status line). Triggered by header-flood traffic or, rarely, by a legitimate API that attaches dozens of custom headers.
Common situations: DoS/header-flood attacks; crawlers or SDKs that attach many trace/debug headers; legitimate but unusual APIs that exceed 128 distinct headers; or a client loop that accidentally stacks headers.
Related errors
- Got more than {limit} bytes when reading: {line!r}.
- Too many trailers received
- compress can not be set if Content-Encoding header is set
- chunked can not be set if "Transfer-Encoding: chunked" heade
- Duplicate '{name}' header found.
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/ad5b6510269fa4e5.json.
Report an issue: GitHub.