{"record":{"id":"4eca35dd687b2234","repo":"denoland/deno","slug":"err-invalid-http-token-4eca35","errorCode":"ERR_INVALID_HTTP_TOKEN","errorMessage":"Header name must be a valid HTTP token [\"${name}\"]","messagePattern":"Header name must be a valid HTTP token \\[\"(.+?)\"\\]","errorType":"validation","errorClass":"NodeTypeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/http2/compat.js","lineNumber":99,"sourceCode":"const kRawTrailers = Symbol(\"rawTrailers\");\nconst kSetHeader = Symbol(\"setHeader\");\nconst kAppendHeader = Symbol(\"appendHeader\");\nconst 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","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/http2/compat.js#L81-L117","documentation":"http2 compat validates every header passing through Http2ServerResponse.setHeader/appendHeader/setTrailer/writeHead via assertValidHeader. A header name that is empty, not a string, or contains a space is rejected with ERR_INVALID_HTTP_TOKEN because HTTP header names must be RFC 7230 tokens (alphanumerics and !#$%&'*+-.^_`|~).","triggerScenarios":"response.setHeader(\"\", value); setHeader(\"content type\", v) with a space in the name; passing a non-string key (number, symbol from Object.keys of a Map); header names built from user input containing spaces, unicode, or control characters.","commonSituations":"Proxies/gateways forwarding arbitrary client-supplied header names; names derived from filenames, IDs, or locale strings; header-injection payloads ('x-inject\\r\\nHost:...') reaching the validator; code ported from http1 stacks that were lenient.","solutions":["Sanitize dynamic names to token characters: /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$/ — replace or drop invalid ones","Map user-controlled values onto a fixed allow-list of header names instead of using them as names","Coerce keys with String(key).trim() and skip empty results","If the data is dirty, put it in the header value (encodeURIComponent) and use a constant name"],"exampleFix":"// before\nconst name = `trace-${userTag}`; // userTag = \"my tag\"\nresponse.setHeader(name, \"1\"); // ERR_INVALID_HTTP_TOKEN\n\n// after\nconst name = `trace-${String(userTag).trim().replace(/[^!#$%&'*+\\-.^_`|~0-9A-Za-z]/g, \"-\")}`;\nif (name) response.setHeader(name, \"1\");","handlingStrategy":"validation","validationCode":"const TOKEN_RE = /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$/;\nfunction safeHeaderName(name) {\n  const s = String(name).trim();\n  return TOKEN_RE.test(s) ? s : null;\n}\nconst safe = safeHeaderName(userSuppliedName);\nif (safe) res.setHeader(safe, value);","typeGuard":"function isValidHeaderName(name: unknown): name is string {\n  return typeof name === \"string\" && name.length > 0 &&\n    /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$/.test(name);\n}","tryCatchPattern":"try {\n  res.setHeader(name, value);\n} catch (err) {\n  if (err.code === \"ERR_INVALID_HTTP_TOKEN\") return; // skip bad name, keep serving\n  throw err;\n}","preventionTips":["Allow-list header names; let user input control only values","Validate names at the trust boundary (request parsing), not at setHeader time","Unit-test that every header your service emits matches the token regex"],"tags":["http2","headers","validation","security"],"backgroundTag":"invalid-http-header","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}