{"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":"validation","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/89f33cbef296a2b287f323d42de54c871fa69c77/ext/http/02_websocket.ts#L45-L81","documentation":"Third handshake check in Deno.upgradeWebSocket: the 'sec-websocket-key' header must be present (non-null). This base64 16-byte nonce is required by RFC 6455 and is also fed to op_http_websocket_accept_header to compute the Sec-WebSocket-Accept reply, so a missing key cannot be defaulted.","triggerScenarios":"Hand-rolled clients or test scripts that send Upgrade/Connection but omit Sec-WebSocket-Key; proxies stripping less common headers; malformed requests replayed from captured traffic where the header was redacted; HTTP/1.0-style requests.","commonSituations":"Custom embedded clients implementing WS by hand; security appliances filtering WebSocket headers; integration tests using raw TCP/HTTP sockets; curl-based smoke tests that only mimic the two obvious headers.","solutions":["Use a real WebSocket client (browser WebSocket, ws package, or Deno's WebSocket) which always sends the key.","If testing by hand, include a valid key: curl -H 'Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==' -H 'Upgrade: websocket' -H 'Connection: Upgrade' -H 'Sec-WebSocket-Version: 13' ...","Check proxies/agents for header stripping and whitelist sec-websocket-* headers.","Pre-check req.headers.has('sec-websocket-key') before calling upgradeWebSocket and answer 400 otherwise."],"exampleFix":"// before\n// hand-rolled client omitted Sec-WebSocket-Key; server:\nconst { response } = Deno.upgradeWebSocket(req); // throws\n\n// after\nif (!req.headers.has(\"sec-websocket-key\")) {\n  return new Response(\"missing sec-websocket-key\", { status: 400 });\n}\nconst { socket, response } = Deno.upgradeWebSocket(req);","handlingStrategy":"validation","validationCode":"if (!req.headers.has(\"sec-websocket-key\")) {\n  return new Response(\"missing sec-websocket-key\", { status: 400 });\n}","typeGuard":"function hasWsKey(req: Request): boolean { return req.headers.has(\"sec-websocket-key\"); }","tryCatchPattern":"try { return Deno.upgradeWebSocket(req).response; } catch (e) { if (e instanceof TypeError && e.message.includes(\"sec-websocket-key\")) { return new Response(\"bad websocket handshake\", { status: 400 }); } throw e; }","preventionTips":["Use spec-compliant WS clients (browser WebSocket, ws, Deno.connect-backed).","When hand-testing with curl, include Sec-WebSocket-Key/Version headers.","Ensure middleboxes don't strip sec-* headers."],"tags":["websocket","http-headers","handshake","rfc6455"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}