{"record":{"id":"4903482159249461","repo":"denoland/deno","slug":"err-http2-invalid-connection-headers","errorCode":"ERR_HTTP2_INVALID_CONNECTION_HEADERS","errorMessage":"HTTP/1 Connection specific headers are forbidden: \"${key}\"","messagePattern":"HTTP/1 Connection specific headers are forbidden: \"(.+?)\"","errorType":"validation","errorClass":"NodeTypeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/http2/util.ts","lineNumber":872,"sourceCode":"    }\n    const flags = ArrayPrototypeIncludes(neverIndex, key)\n      ? kNeverIndexFlag\n      : kNoHeaderFlags;\n    if (key[0] === \":\") {\n      const err = assertValuePseudoHeader(key);\n      if (err !== undefined) {\n        throw err;\n      }\n      value = escapeNgHeaderValueZeroBytes(value);\n      pseudoHeaders += `${key}\\0${value}\\0${flags}`;\n      count++;\n      return;\n    }\n    if (!checkIsHttpToken(key)) {\n      throw new ERR_INVALID_HTTP_TOKEN(\"Header name\", key);\n    }\n    if (isIllegalConnectionSpecificHeader(key, value)) {\n      throw new ERR_HTTP2_INVALID_CONNECTION_HEADERS(key);\n    }\n    if (isArray) {\n      for (let j = 0; j < value.length; ++j) {\n        const val = escapeNgHeaderValueZeroBytes(String(value[j]));\n        headers += `${key}\\0${val}\\0${flags}`;\n      }\n      count += value.length;\n      return;\n    }\n    value = escapeNgHeaderValueZeroBytes(value);\n    headers += `${key}\\0${value}\\0${flags}`;\n    count++;\n  }\n\n  if (ArrayIsArray(arrayOrMap)) {\n    for (let i = 0; i < arrayOrMap.length; i += 2) {\n      const key = arrayOrMap[i];\n      const value = arrayOrMap[i + 1];","sourceCodeStart":854,"sourceCodeEnd":890,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/http2/util.ts#L854-L890","documentation":"HTTP/2 forbids HTTP/1.1 connection-control headers: connection, upgrade, http2-settings, keep-alive, proxy-connection, transfer-encoding, and te unless its value is exactly 'trailers' (isIllegalConnectionSpecificHeader, util.ts:595). Any of these in a header set throws ERR_HTTP2_INVALID_CONNECTION_HEADERS (util.ts:872) before HPACK serialization.","triggerScenarios":"Passing headers such as { connection: 'keep-alive' }, { 'transfer-encoding': 'chunked' }, { upgrade: 'websocket' } or { te: 'gzip' } to http2session.request()/stream.respond(); te: 'trailers' is the sole permitted value.","commonSituations":"Porting HTTP/1.1 client/server code that set Connection/Transfer-Encoding manually; proxies forwarding upstream HTTP/1.1 headers verbatim into an HTTP/2 request; frameworks that blanket-add connection: keep-alive; misconfigured websocket-over-h2 attempts using the HTTP/1 Upgrade header.","solutions":["Strip the forbidden headers before the call: delete connection, upgrade, http2-settings, keep-alive, proxy-connection, transfer-encoding (and te unless 'trailers').","In proxies, translate instead of forwarding: drop hop-by-hop headers per RFC 7230 section 6.1.","Use the dedicated websocket-over-HTTP/2 (RFC 8441 :protocol) API rather than upgrade headers."],"exampleFix":"// before\nsession.request({ ':method': 'GET', ':path': '/', connection: 'keep-alive', 'transfer-encoding': 'chunked' });\n\n// after\nconst HOP = ['connection', 'upgrade', 'http2-settings', 'keep-alive', 'proxy-connection', 'transfer-encoding'];\nconst clean = Object.fromEntries(Object.entries(h).filter(([k]) => !HOP.includes(k.toLowerCase())));\nsession.request({ ':method': 'GET', ':path': '/', ...clean });","handlingStrategy":"validation","validationCode":"const HOP_BY_HOP = new Set(['connection', 'upgrade', 'http2-settings', 'keep-alive', 'proxy-connection', 'transfer-encoding']);\nconst clean = Object.fromEntries(\n  Object.entries(h).filter(([k, v]) =>\n    !(HOP_BY_HOP.has(k.toLowerCase()) || (k.toLowerCase() === 'te' && v !== 'trailers'))\n  ),\n);","typeGuard":"const isForbiddenConnectionHeader = (k: string, v: string) =>\n  ['connection', 'upgrade', 'http2-settings', 'keep-alive', 'proxy-connection', 'transfer-encoding'].includes(k.toLowerCase()) ||\n  (k.toLowerCase() === 'te' && v !== 'trailers');","tryCatchPattern":null,"preventionTips":["Strip hop-by-hop headers at every HTTP/1 -> HTTP/2 boundary","Use :protocol (RFC 8441) for websockets over h2, not upgrade headers"],"tags":["http2","headers","proxy","hop-by-hop","node-compat"],"backgroundTag":"connection-specific-headers","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}