{"id":"e2431647ff938fdb","repo":"aio-libs/aiohttp","slug":"duplicate-name-header-found","errorCode":null,"errorMessage":"Duplicate '{name}' header found.","messagePattern":"Duplicate '(.+?)' header found\\.","errorType":"http","errorClass":"BadHttpMessage","httpStatus":400,"severity":"error","filePath":"aiohttp/http_parser.py","lineNumber":237,"sourceCode":"                        if line:\n                            continuation = line[0] in (32, 9)  # (' ', '\\t')\n                    else:\n                        line = b\"\"\n                        break\n                bvalue = b\"\".join(bvalue_lst)\n\n            bvalue = bvalue.strip(b\" \\t\")\n            value = bvalue.decode(\"utf-8\", \"surrogateescape\")\n\n            # https://www.rfc-editor.org/rfc/rfc9110.html#section-5.5-5\n            if self._lax:\n                if \"\\n\" in value or \"\\r\" in value or \"\\x00\" in value:\n                    raise InvalidHeader(bvalue)\n            elif _FIELD_VALUE_FORBIDDEN_CTL_RE.search(value):\n                raise InvalidHeader(bvalue)\n\n            if not self._lax and name in headers and name.lower() in SINGLETON_HEADERS:\n                raise BadHttpMessage(f\"Duplicate '{name}' header found.\")\n            headers.add(name, value)\n            raw_headers.append((bname, bvalue))\n\n        return (HeadersDictProxy(headers), tuple(raw_headers))\n\n\ndef _is_supported_upgrade(headers: HeadersDictProxy) -> bool:\n    \"\"\"Check if the upgrade header is supported.\"\"\"\n    u = headers.get(hdrs.UPGRADE, \"\")\n    # .lower() can transform non-ascii characters.\n    return u.isascii() and u.lower() in {\"tcp\", \"websocket\"}\n\n\nclass HttpParser(abc.ABC, Generic[_MsgT]):\n    lax: ClassVar[bool] = False\n\n    def __init__(\n        self,","sourceCodeStart":219,"sourceCodeEnd":255,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/http_parser.py#L219-L255","documentation":"Raised by HeadersParser.parse_headers (aiohttp/http_parser.py:237) in strict mode (request parser) when a header name appears more than once AND its lowercased name is in SINGLETON_HEADERS: content-length, content-location, content-range, content-type, etag, host, max-forwards, server, transfer-encoding, user-agent. RFC 9110 sections 8.1/8.3 require these appear at most once. The lax response parser skips this check because real-world servers (Google APIs, Werkzeug, etc.) commonly send duplicate Content-Type/Server.","triggerScenarios":"A request containing two of any singleton header - e.g. two Host: lines, two Content-Length: lines, or two Content-Type: lines. Duplicate Content-Length is the classic request-smuggling vector; duplicate User-Agent often comes from proxies appending their own.","commonSituations":"Request-smuggling attacks (duplicate Content-Length), proxies or SDKs that append a second User-Agent/Host, naive clients that call headers.add() instead of assignment, or buggy gateways that duplicate Content-Type.","solutions":["Send each singleton header exactly once; use assignment (headers[name] = value) rather than headers.add() for these fields.","If you combine headers from multiple sources, deduplicate singleton names before sending.","On the server side, aiohttp returns 400 automatically; log and alert on duplicates since they often indicate smuggling.","Audit any proxy in the chain that may append a duplicate singleton."],"exampleFix":"# before - .add() can stack duplicates\nheaders.add('Host', 'a.com')\nheaders.add('Host', 'b.com')   # duplicate -> rejected\n# after - assignment replaces\nheaders['Host'] = 'a.com'","handlingStrategy":"validation","validationCode":"from aiohttp.http_parser import SINGLETON_HEADERS\ndef has_duplicate_singletons(headers):\n    seen, dups = set(), set()\n    for k in headers.keys():\n        lk = k.lower()\n        if lk in SINGLETON_HEADERS:\n            (dups if lk in seen else seen).add(lk)\n    return dups\nif has_duplicate_singletons(outgoing):\n    raise ValueError('duplicate singleton header')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use headers[name] = value (replace) instead of headers.add() for singleton fields","Audit proxies that may append duplicate User-Agent/Host/Content-Type","Treat duplicate Content-Length as a security incident"],"tags":["http","headers","security","request-smuggling","parser","request"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}