{"record":{"id":"934a66b8449aaeba","repo":"denoland/deno","slug":"invalid-header-sec-websocket-key-header-must-be","errorCode":null,"errorMessage":"Invalid Header: 'sec-websocket-key' header must be set","messagePattern":"Invalid Header: 'sec-websocket-key' header must be set","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/http/02_websocket.ts","lineNumber":63,"sourceCode":"    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],\n  ];\n\n  const protocolsStr = request.headers.get(\"sec-websocket-protocol\") || \"\";\n  const protocols = StringPrototypeSplit(protocolsStr, \", \");\n  if (protocols && options.protocol) {\n    if (ArrayPrototypeIncludes(protocols, options.protocol)) {\n      ArrayPrototypePush(r.headerList, [","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/http/02_websocket.ts#L45-L81","documentation":"RFC 6455 requires the client to send a random `Sec-WebSocket-Key`; the server hashes it to produce `Sec-WebSocket-Accept`. `Deno.upgradeWebSocket` reads it via `request.headers.get('sec-websocket-key')` and throws this TypeError when it is absent, because the accept header — and therefore a valid 101 response — cannot be computed.","triggerScenarios":"Non-browser clients (raw TCP scripts, custom embedded clients, curl) that send Upgrade/Connection headers but no key; intermediaries stripping `Sec-*` headers; replayed or crafted requests.","commonSituations":"Load balancers or WAFs dropping unrecognized `Sec-WebSocket-*` headers; IoT/embedded clients with incomplete handshake implementations; test harnesses issuing partial handshakes.","solutions":["Use a spec-compliant WebSocket client (browser WebSocket, or a ws library)","Fix the proxy/WAF to forward all `Sec-WebSocket-*` headers","Validate the handshake headers up front and answer 400 for incomplete ones"],"exampleFix":"// before\nconst ws = Deno.upgradeWebSocket(request);\n\n// after\nif (request.headers.get(\"sec-websocket-key\") === null) {\n  return new Response(\"Missing Sec-WebSocket-Key\", { status: 400 });\n}\nconst ws = Deno.upgradeWebSocket(request);","handlingStrategy":"validation","validationCode":"if (request.headers.get(\"sec-websocket-key\") === null) {\n  return new Response(\"Missing Sec-WebSocket-Key\", { status: 400 });\n}\nconst ws = Deno.upgradeWebSocket(request);","typeGuard":"const hasWebSocketKey = (req: Request): boolean =>\n  req.headers.has(\"sec-websocket-key\");","tryCatchPattern":"try {\n  return Deno.upgradeWebSocket(request);\n} catch (err) {\n  if (err instanceof TypeError && err.message.includes(\"sec-websocket-key\")) {\n    return new Response(\"Incomplete WebSocket handshake\", { status: 400 });\n  }\n  throw err;\n}","preventionTips":["Use spec-compliant WebSocket clients for integration tests","Audit WAF/proxy rules so Sec-WebSocket-* headers survive the hop","Reject incomplete handshakes with 400 before they reach upgrade code"],"tags":["websocket","http","handshake","headers"],"backgroundTag":"websocket-upgrade-failed","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}