{"record":{"id":"f5a07253bb7aa0d2","repo":"denoland/deno","slug":"err-http2-status-101","errorCode":"ERR_HTTP2_STATUS_101","errorMessage":"HTTP status code 101 (Switching Protocols) is forbidden in HTTP/2","messagePattern":"HTTP status code 101 \\(Switching Protocols\\) is forbidden in HTTP/2","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/http2.ts","lineNumber":3460,"sourceCode":"  // a 1xx informational code and it MUST be sent before the request/response\n  // headers are sent, or an error will be thrown.\n  additionalHeaders(headers) {\n    if (this.destroyed || this.closed) {\n      throw new ERR_HTTP2_INVALID_STREAM();\n    }\n    if (this.headersSent) {\n      throw new ERR_HTTP2_HEADERS_AFTER_RESPOND();\n    }\n\n    assertIsObject(headers, \"headers\");\n    headers = ObjectAssign({ __proto__: null }, headers);\n\n    debugStreamObj(this, \"sending additional headers\");\n\n    if (headers[HTTP2_HEADER_STATUS] != null) {\n      const statusCode = headers[HTTP2_HEADER_STATUS] |= 0;\n      if (statusCode === HTTP_STATUS_SWITCHING_PROTOCOLS) {\n        throw new ERR_HTTP2_STATUS_101();\n      }\n      if (statusCode < 100 || statusCode >= 200) {\n        throw new ERR_HTTP2_INVALID_INFO_STATUS(headers[HTTP2_HEADER_STATUS]);\n      }\n    }\n\n    this[kUpdateTimer]();\n\n    const headersList = buildNgHeaderString(\n      headers,\n      assertValidPseudoHeaderResponse,\n      this.session[kStrictSingleValueFields],\n    );\n    if (!this[kInfoHeaders]) {\n      this[kInfoHeaders] = [headers];\n    } else {\n      ArrayPrototypePush(this[kInfoHeaders], headers);\n    }","sourceCodeStart":3442,"sourceCodeEnd":3478,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/http2.ts#L3442-L3478","documentation":"HTTP/2 removed the HTTP/1.1 Upgrade mechanism, so status 101 (Switching Protocols) is explicitly forbidden on an HTTP/2 stream. additionalHeaders() throws ERR_HTTP2_STATUS_101 when the informational header block carries :status 101 — WebSockets-over-Upgrade cannot work this way in h2.","triggerScenarios":"Passing { ':status': 101 } (or any headers object whose :status coerces to 101) to additionalHeaders(); porting HTTP/1.1 WebSocket-upgrade middleware onto an http2 server; forwarding 101 from an upstream.","commonSituations":"Running WebSocket code on an h2-only server (RFC 8441 bootstraps WebSockets differently, via CONNECT with :protocol); proxies translating h1 upgrade responses into h2.","solutions":["Use the RFC 8441 extended CONNECT (:method CONNECT + :protocol websocket) instead of 101","Serve WebSocket traffic on a separate HTTP/1.1 listener or h2 prior-knowledge-free endpoint","If you control the protocol, answer with a normal 200 and switch at the application layer","Strip :status 101 before relaying upstream headers into additionalHeaders()"],"exampleFix":"// before\nstream.additionalHeaders({ \":status\": 101, upgrade: \"websocket\" });\n\n// after\n// RFC 8441: no 101 in h2; use extended CONNECT on the session\n// const stream = session.request({ \":method\": \"CONNECT\", \":path\": \"/chat\", \":protocol\": \"websocket\" });","handlingStrategy":"validation","validationCode":"const status = headers[\":status\"];\nif (status === 101) {\n  throw new Error(\"101 Switching Protocols is impossible over HTTP/2; use RFC 8441 CONNECT or a separate h1 endpoint\");\n}","typeGuard":"function isH2SafeInfoStatus(status) {\n  const n = Number(status);\n  return Number.isInteger(n) && n >= 100 && n < 200 && n !== 101;\n}","tryCatchPattern":"try {\n  stream.additionalHeaders(headers);\n} catch (err) {\n  if (err.code === \"ERR_HTTP2_STATUS_101\") {\n    // fall back: negotiate WebSocket outside h2 or reject the upgrade\n    stream.respond({ \":status\": 501 }, { endStream: true });\n    return;\n  }\n  throw err;\n}","preventionTips":["Do not port HTTP/1.1 Upgrade middleware onto an http2 server","Bootstrap WebSockets over h2 with extended CONNECT (:protocol), per RFC 8441"],"tags":["http2","node-compat","websocket","status-code","deno"],"backgroundTag":"http2-status-code-invalid","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}