{"record":{"id":"7c22537f78456a20","repo":"denoland/deno","slug":"err-http2-invalid-info-status","errorCode":"ERR_HTTP2_INVALID_INFO_STATUS","errorMessage":"Invalid informational status code: ${headers[HTTP2_HEADER_STATUS]}","messagePattern":"Invalid informational status code: (.+?)","errorType":"exception","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/http2.ts","lineNumber":3463,"sourceCode":"    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    }\n\n    const ret = this[kHandle].info(headersList[0], headersList[1]);\n    if (ret < 0) {","sourceCodeStart":3445,"sourceCodeEnd":3481,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/http2.ts#L3445-L3481","documentation":"additionalHeaders() may only carry informational status codes: 100-199 excluding 101 (which has its own error). Any :status below 100, at or above 200, or a non-coercible value (bitwise |= 0 turns '103abc' into garbage) throws ERR_HTTP2_INVALID_INFO_STATUS.","triggerScenarios":"Passing ':status': 200/204 to additionalHeaders(); forwarding a final upstream status into the hints path; a string status like '103' only working by accident while others coerce to out-of-range numbers.","commonSituations":"Hint middleware reusing the real response headers object; copy-paste of respond() headers into additionalHeaders(); logging/status plumbing that assumes any status is valid anywhere.","solutions":["Only ever send 100-199 (typically 103) via additionalHeaders(); send final statuses with respond()","Build the hints object explicitly with __proto__: null and only 1xx :status + link headers","Validate statusCode >= 100 && statusCode < 200 && statusCode !== 101 before the call","Keep hint headers and final headers in separate constants so they cannot be swapped"],"exampleFix":"// before\nstream.additionalHeaders(responseHeaders); // contains \":status\": 200\n\n// after\nconst hints = Object.assign(Object.create(null), {\n  \":status\": 103,\n  link: \"</style.css>; rel=preload\",\n});\nstream.additionalHeaders(hints);","handlingStrategy":"validation","validationCode":"const status = Number(headers[\":status\"]);\nif (!(Number.isInteger(status) && status >= 100 && status < 200 && status !== 101)) {\n  return; // not a valid informational code; skip hints\n}\nstream.additionalHeaders(headers);","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_INVALID_INFO_STATUS\") return; // bad hint value; skip\n  throw err;\n}","preventionTips":["Build hint objects separately from final response headers; never reuse the respond() headers","Hard-code ':status': 103 for Early Hints instead of forwarding variable statuses"],"tags":["http2","node-compat","early-hints","status-code","argument-validation","deno"],"backgroundTag":"http2-status-code-invalid","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}