{"record":{"id":"23a8ec58ccae8024","repo":"denoland/deno","slug":"err-http2-pseudoheader-not-allowed","errorCode":"ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED","errorMessage":"Cannot set HTTP/2 pseudo-headers","messagePattern":"Cannot set HTTP/2 pseudo-headers","errorType":"validation","errorClass":"NodeTypeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/http2/compat.js","lineNumber":102,"sourceCode":"const kAborted = Symbol(\"aborted\");\n\nlet statusMessageWarned = false;\nlet statusConnectionHeaderWarned = false;\n\n// Defines and implements an API compatibility layer on top of the core\n// HTTP/2 implementation, intended to provide an interface that is as\n// close as possible to the current require('http') API\n\nconst assertValidHeader = hideStackFrames((name, value) => {\n  if (\n    name === \"\" ||\n    typeof name !== \"string\" ||\n    StringPrototypeIncludes(name, \" \")\n  ) {\n    throw new ERR_INVALID_HTTP_TOKEN.HideStackFramesError(\"Header name\", name);\n  }\n  if (isPseudoHeader(name)) {\n    throw new ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED.HideStackFramesError();\n  }\n  if (value === undefined || value === null) {\n    throw new ERR_HTTP2_INVALID_HEADER_VALUE.HideStackFramesError(value, name);\n  }\n  if (!isConnectionHeaderAllowed(name, value)) {\n    connectionHeaderMessageWarn();\n  }\n});\n\nfunction isPseudoHeader(name) {\n  switch (name) {\n    case HTTP2_HEADER_STATUS: // :status\n    case HTTP2_HEADER_METHOD: // :method\n    case HTTP2_HEADER_PATH: // :path\n    case HTTP2_HEADER_AUTHORITY: // :authority\n    case HTTP2_HEADER_SCHEME: // :scheme\n      return true;\n    default:","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/http2/compat.js#L84-L120","documentation":"The same assertValidHeader in http2 compat rejects pseudo-headers — names beginning with ':' such as :status, :method, :path, :authority, :scheme — with ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED. In HTTP/2 these fields are protocol metadata carried outside the header block, so the generic header APIs (setHeader, appendHeader, setTrailer/addTrailers) refuse them.","triggerScenarios":"response.setHeader(\":status\", 200); response.addTrailers({ \":status\": 200 }); copying an incoming h2 request's raw headers object (which contains :method/:path/:authority) directly onto an outgoing response via setHeader loops.","commonSituations":"Copy-forward proxies replaying h2 header objects; code ported from the h2 client API (h2.request legitimately takes :method/:path) into server response APIs; generic header middleware that serializes metadata as ':'-prefixed keys.","solutions":["Use the dedicated APIs: response.statusCode for :status, request.method / request.url for :method/:path","Strip pseudo-headers before forwarding: omit every key starting with ':'","When copying h2 request headers, map :authority to host and drop the rest"],"exampleFix":"// before\nresponse.setHeader(\":status\", 201); // ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED\n\n// after\nresponse.statusCode = 201;","handlingStrategy":"validation","validationCode":"function stripPseudoHeaders(headers) {\n  return Object.fromEntries(\n    Object.entries(headers).filter(([k]) => !k.startsWith(\":\")),\n  );\n}\nres.writeHead(200, stripPseudoHeaders(incomingHttp2Headers));","typeGuard":"function isPseudoHeader(name: string): boolean {\n  return name.startsWith(\":\");\n}","tryCatchPattern":"try {\n  res.setHeader(name, value);\n} catch (err) {\n  if (err.code === \"ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED\") {\n    if (name === \":status\") res.statusCode = Number(value);\n    return;\n  }\n  throw err;\n}","preventionTips":["Never let ':'-prefixed keys reach setHeader/appendHeader/addTrailers","Use statusCode/stream APIs for h2 metadata instead of header-shaped syntax"],"tags":["http2","headers","pseudo-headers"],"backgroundTag":"invalid-http-header","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"}