{"record":{"id":"e2431647ff938fdb","repo":"aio-libs/aiohttp","slug":"duplicate-name-header-found","errorCode":null,"errorMessage":"Duplicate '{name}' header found.","messagePattern":"Duplicate '(.+?)' header found\\.","errorType":"exception","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/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/http_parser.py#L219-L255","documentation":"Raised in strict mode (self._lax=False, request parser default) when a header whose lowercased name is in SINGLETON_HEADERS appears more than once. Singletons per RFC 9110: content-length, content-location, content-range, content-type, etag, host, max-forwards, server, transfer-encoding, user-agent. Lax mode (response parsing) skips this check because real servers (Google APIs, Werkzeug) commonly send duplicates.","triggerScenarios":"A client sends two Host: lines, two Content-Length: lines, or any other duplicate singleton in strict mode.","commonSituations":"Custom clients calling headers.add() twice for a singleton, proxies appending duplicates, malformed test fixtures, deliberate smuggling (duplicate CL is the classic technique).","solutions":["Send each singleton header exactly once.","Use assignment (headers['Host'] = ...) or setdefault instead of headers.add() for singletons.","Audit middleware that appends headers without checking presence."],"exampleFix":"# before\nheaders.add('Host', 'a')\nheaders.add('Host', 'b')   # duplicate\n\n# after - assign, which replaces\nheaders['Host'] = 'a'","handlingStrategy":"validation","validationCode":"SINGLETONS = {'content-length','content-location','content-range','content-type','etag','host','max-forwards','server','transfer-encoding','user-agent'}\ndef dedupe_singletons(headers):\n    seen = set()\n    for k in list(headers):\n        lk = k.lower()\n        if lk in SINGLETONS:\n            if lk in seen:\n                del headers[k]\n            else:\n                seen.add(lk)","typeGuard":"SINGLETONS = {'content-length','content-location','content-range','content-type','etag','host','max-forwards','server','transfer-encoding','user-agent'}\ndef singleton_sent_once(names):\n    lower = [n.lower() for n in names]\n    return all(lower.count(s) <= 1 for s in SINGLETONS)","tryCatchPattern":"from aiohttp.http_exceptions import BadHttpMessage\ntry:\n    ...parse...\nexcept BadHttpMessage as e:\n    # message includes which singleton duplicated; close the connection\n    ...","preventionTips":["Prefer headers['Name'] = value (replace) over headers.add() for singletons.","Remember lax mode tolerates duplicates; strict mode does not - test with the strict request parser."],"tags":["http","parser","header","security","validation"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}