{"record":{"id":"872204b8bf6ba3a5","repo":"denoland/deno","slug":"err-http2-invalid-pseudoheader","errorCode":"ERR_HTTP2_INVALID_PSEUDOHEADER","errorMessage":"\"${key}\" is an invalid pseudoheader or is used incorrectly","messagePattern":"\"(.+?)\" is an invalid pseudoheader or is used incorrectly","errorType":"validation","errorClass":"NodeTypeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/http2/util.ts","lineNumber":613,"sourceCode":"function isIllegalConnectionSpecificHeader(name, value) {\n  switch (name) {\n    case HTTP2_HEADER_CONNECTION:\n    case HTTP2_HEADER_UPGRADE:\n    case HTTP2_HEADER_HTTP2_SETTINGS:\n    case HTTP2_HEADER_KEEP_ALIVE:\n    case HTTP2_HEADER_PROXY_CONNECTION:\n    case HTTP2_HEADER_TRANSFER_ENCODING:\n      return true;\n    case HTTP2_HEADER_TE:\n      return value !== \"trailers\";\n    default:\n      return false;\n  }\n}\n\nconst assertValidPseudoHeader = hideStackFrames((key) => {\n  if (!kValidPseudoHeaders.has(key)) {\n    throw new ERR_HTTP2_INVALID_PSEUDOHEADER(key);\n  }\n});\n\nconst assertValidPseudoHeaderResponse = hideStackFrames((key) => {\n  if (key !== \":status\") {\n    throw new ERR_HTTP2_INVALID_PSEUDOHEADER(key);\n  }\n});\n\nconst assertValidPseudoHeaderTrailer = hideStackFrames((key) => {\n  throw new ERR_HTTP2_INVALID_PSEUDOHEADER(key);\n});\n\n/**\n * Takes a request headers array, validates it and sets defaults, and returns\n * the resulting headers in NgHeaders string list format.\n * @returns {object}\n */","sourceCodeStart":595,"sourceCodeEnd":631,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/http2/util.ts#L595-L631","documentation":"HTTP/2 pseudo-headers (keys starting with ':') are fixed by RFC 7540; only :status, :method, :authority, :scheme, :path and :protocol are legal (kValidPseudoHeaders, util.ts:120). When request headers are prepared, every ':'-prefixed key is checked against that set and any other pseudo-header throws ERR_HTTP2_INVALID_PSEUDOHEADER.","triggerScenarios":"Passing a request headers array containing a ':'-prefixed key outside the valid set, e.g. [':method','GET', ':custom','x'] to http2session.request() or client.request(); assertValidPseudoHeader (util.ts:611) rejects ':custom'.","commonSituations":"Forwarding arbitrary header maps from proxies/gateways that already mangled ':'-prefixed names, building headers dynamically from user input where a stray ':' prefixes a normal header, or copying gRPC-style metadata (':path' ok, ':grpc-custom' not) into plain HTTP/2 requests.","solutions":["Inspect the thrown message for the offending key and rename it to a normal header without the leading ':' (unless it is one of the six standard pseudo-headers).","If you are proxying, strip or map unknown ':'-prefixed keys before calling request().","Use the constants http2.constants.HTTP2_HEADER_METHOD / :PATH / :AUTHORITY / :SCHEME / :PROTOCOL / :STATUS instead of hand-typing pseudo-header names."],"exampleFix":"// before\nconst headers = [':method', 'GET', ':ver', '2']; // ':ver' is not a pseudo-header\n\n// after\nconst headers = [':method', 'GET', 'x-ver', '2'];","handlingStrategy":"validation","validationCode":"const VALID = new Set([':status', ':method', ':authority', ':scheme', ':path', ':protocol']);\nconst safe = headers.filter((k, i) => i % 2 === 1 || !String(k).startsWith(':') || VALID.has(k));","typeGuard":"const isPseudoHeader = (k: string) => k.startsWith(':');\nconst isValidPseudo = (k: string) =>\n  [':status', ':method', ':authority', ':scheme', ':path', ':protocol'].includes(k);","tryCatchPattern":"try { client.request(h); } catch (e) { if (e.code === 'ERR_HTTP2_INVALID_PSEUDOHEADER') { /* message contains the bad key; rename or strip it */ } throw e; }","preventionTips":["Use http2.constants.HTTP2_HEADER_* instead of hand-written ':'-keys","Filter ':'-prefixed keys from foreign/proxied header maps before request()"],"tags":["http2","headers","pseudo-header","node-compat"],"backgroundTag":"invalid-pseudo-header","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}