{"record":{"id":"f0897b0aeef6606e","repo":"denoland/deno","slug":"invalid-header-connection-header-must-contain","errorCode":null,"errorMessage":"Invalid Header: 'connection' header must contain 'Upgrade'","messagePattern":"Invalid Header: 'connection' header must contain 'Upgrade'","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/http/02_websocket.ts","lineNumber":56,"sourceCode":"function upgradeWebSocket(request, options = { __proto__: null }) {\n  const inner = toInnerRequest(request);\n  if (inner._wantsUpgrade) {\n    inner._throwIfUpgraded();\n  }\n  const upgrade = request.headers.get(\"upgrade\");\n  const upgradeHasWebSocketOption = upgrade !== null &&\n    websocketCvf(upgrade);\n  if (!upgradeHasWebSocketOption) {\n    throw new TypeError(\n      \"Invalid Header: 'upgrade' header must contain 'websocket'\",\n    );\n  }\n\n  const connection = request.headers.get(\"connection\");\n  const connectionHasUpgradeOption = connection !== null &&\n    upgradeCvf(connection);\n  if (!connectionHasUpgradeOption) {\n    throw new TypeError(\n      \"Invalid Header: 'connection' header must contain 'Upgrade'\",\n    );\n  }\n\n  const websocketKey = request.headers.get(\"sec-websocket-key\");\n  if (websocketKey === null) {\n    throw new TypeError(\n      \"Invalid Header: 'sec-websocket-key' header must be set\",\n    );\n  }\n\n  const accept = op_http_websocket_accept_header(websocketKey);\n\n  const r = newInnerResponse(101);\n  r.headerList = [\n    [\"upgrade\", \"websocket\"],\n    [\"connection\", \"Upgrade\"],\n    [\"sec-websocket-accept\", accept],","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/http/02_websocket.ts#L38-L74","documentation":"Second handshake check in Deno.upgradeWebSocket: the 'connection' header must contain the token 'Upgrade' (case-insensitive comma list, via upgradeCvf). This is part of RFC 6455's handshake (Connection: Upgrade); its absence means the request is not a protocol upgrade request.","triggerScenarios":"Handshake requests where a client or intermediary sent Upgrade: websocket but Connection: keep-alive/close; proxies that forward one hop header but rewrite Connection; hand-crafted HTTP clients that set only the upgrade header; HTTP/2 pseudo-upgrade attempts mapped onto HTTP/1 semantics without the header.","commonSituations":"Misconfigured reverse proxies or CDNs that drop the Connection header (hop-by-hop header, must be explicitly re-set); custom embedded HTTP clients; API gateways terminating WS.","solutions":["Guard before upgrading: parse req.headers.get('connection') and require the 'upgrade' token (case-insensitive) before calling Deno.upgradeWebSocket.","Configure the proxy to set Connection: upgrade when forwarding (nginx: proxy_set_header Connection \"upgrade\").","Use a spec-compliant WebSocket client library rather than hand-written handshake code."],"exampleFix":"// before\nconst { response } = Deno.upgradeWebSocket(req); // Connection: keep-alive -> throws\n\n// after\nconst conn = req.headers.get(\"connection\") ?? \"\";\nif (!conn.toLowerCase().split(',').map((s) => s.trim()).includes(\"upgrade\")) {\n  return new Response(\"not a websocket upgrade\", { status: 400 });\n}\nconst { socket, response } = Deno.upgradeWebSocket(req);","handlingStrategy":"validation","validationCode":"const connectionTokens = (req.headers.get(\"connection\") ?? \"\")\n  .toLowerCase().split(\",\").map((s) => s.trim());\nif (!connectionTokens.includes(\"upgrade\")) {\n  return new Response(\"Connection: Upgrade required\", { status: 400 });\n}","typeGuard":"function hasConnectionUpgrade(req: Request): boolean { return (req.headers.get(\"connection\") ?? \"\").toLowerCase().split(\",\").map((s) => s.trim()).includes(\"upgrade\"); }","tryCatchPattern":"try { return Deno.upgradeWebSocket(req).response; } catch (e) { if (e instanceof TypeError && e.message.includes(\"'connection' header\")) { return new Response(\"expected Connection: Upgrade\", { status: 400 }); } throw e; }","preventionTips":["Configure proxies to re-set hop-by-hop headers (proxy_set_header Connection \"upgrade\").","Validate the full handshake triple (upgrade/connection/key) in one helper before upgrading."],"tags":["websocket","http-headers","connection","proxy"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}