aio-libs/aiohttp · error · BadHttpMessage
Request has duplicate `chunked` Transfer-Encoding
Error message
Request has duplicate `chunked` Transfer-Encoding
What it means
Raised as BadHttpMessage (HTTP 400) when the Transfer-Encoding header contains the 'chunked' coding more than once. RFC 9112 §7.1 forbids applying the chunked transfer coding more than once to a message body. The guard lives in HttpRequestParser._is_chunked_te: it splits TE on commas and counts case-insensitive ASCII 'chunked' tokens; more than one raises.
Solutions
- Send Transfer-Encoding with at most one 'chunked' token (it must be the last token if present).
- Fix the proxy/middleware that is appending 'chunked' a second time to the TE header.
- If you control the client, ensure the TE header is built once and not concatenated across hops.
- Validate outgoing TE headers before sending: a single trailing 'chunked' only.
Example fix
// before Transfer-Encoding: chunked, chunked\r\n // after Transfer-Encoding: chunked\r\n
Defensive patterns
Strategy: validation
Validate before calling
def normalize_transfer_encoding(te: str) -> str:
parts = [p.strip(" \t") for p in te.split(',')]
chunked_count = sum(1 for p in parts if p.isascii() and p.lower() == 'chunked')
if chunked_count > 1:
# collapse duplicates: keep a single trailing 'chunked'
parts = [p for p in parts if not (p.isascii() and p.lower() == 'chunked')]
parts.append('chunked')
return ','.join(parts) Try / catch
from aiohttp.http_exceptions import BadHttpMessage
try:
parser.feed_data(raw)
except BadHttpMessage as e:
respond_400(str(e)) # duplicate chunked / invalid TE Prevention
- Never append 'chunked' to TE without checking it is not already present.
- Build TE once at the origin and do not let intermediaries re-add codings.
- Validate TE headers in test fixtures: at most one trailing 'chunked'.
When it happens
Trigger: A request with 'Transfer-Encoding: chunked, chunked' (or any comma-separated list containing 'chunked' twice). Parsed by _is_chunked_te before the body is read; triggered during parse_headers when the TE header is present.
Common situations: A buggy intermediary (proxy, middleware) that appends 'chunked' to an already-chunked TE header; fuzzing/security scanners probing encoding-handling bugs; misconfigured reverse proxy double-encoding chunked transfers; an HTTP/1.1 client built manually that stacks the encoding.
Related errors
- Request has invalid `Transfer-Encoding`
- Not enough data to satisfy transfer length header.
- chunked can not be set if Content-Length header is set
- chunked can not be set if "Transfer-Encoding: chunked"…
- {path}
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/4d72e200bc582d7f.
Report an issue: GitHub.
Appendix: source
Thrown at aiohttp/http_parser.py:747
path,
version_o,
headers,
raw_headers,
close,
compression,
upgrade,
chunked,
url,
)
def _is_chunked_te(self, te: str) -> bool:
# https://www.rfc-editor.org/rfc/rfc9112#section-7.1-3
# "A sender MUST NOT apply the chunked transfer coding more
# than once to a message body"
parts = [p.strip(" \t") for p in te.split(",")]
chunked_count = sum(1 for p in parts if p.isascii() and p.lower() == "chunked")
if chunked_count > 1:
raise BadHttpMessage("Request has duplicate `chunked` Transfer-Encoding")
last = parts[-1]
# .lower() transforms some non-ascii chars, so must check first.
if last.isascii() and last.lower() == "chunked":
return True
# https://www.rfc-editor.org/rfc/rfc9112#section-6.3-2.4.3
raise BadHttpMessage("Request has invalid `Transfer-Encoding`")
class HttpResponseParser(HttpParser[RawResponseMessage]):
"""Read response status line and headers.
BadStatusLine could be raised in case of any errors in status line.
Returns RawResponseMessage.
"""
protocol: "ResponseHandler"
# Lax mode should only be enabled on response parser.View on GitHub (pinned to d041d4d0fd)