{"record":{"id":"ab08ae6029dd70da","repo":"denoland/deno","slug":"invalid-header-value-value","errorCode":null,"errorMessage":"Invalid header value: \"${value}\"","messagePattern":"Invalid header value: \"(.+?)\"","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/fetch/20_headers.js","lineNumber":176,"sourceCode":"  return valid;\n}\n\n/**\n * https://fetch.spec.whatwg.org/#concept-headers-append\n * @param {Headers} headers\n * @param {string} name\n * @param {string} value\n */\nfunction appendHeader(headers, name, value) {\n  // 1.\n  value = normalizeHeaderValue(value);\n\n  // 2.\n  if (!checkHeaderNameForHttpTokenCodePoint(name)) {\n    throw new TypeError(`Invalid header name: \"${name}\"`);\n  }\n  if (!checkForInvalidValueChars(value)) {\n    throw new TypeError(`Invalid header value: \"${value}\"`);\n  }\n\n  // 3.\n  if (headers[_guard] == \"immutable\") {\n    throw new TypeError(\"Cannot change header: headers are immutable\");\n  }\n\n  // 7.\n  const list = headerListFromHeaders(headers);\n  const lowerNames = ensureLowerNames(headers);\n  const lowercaseName = byteLowerCase(name);\n  for (let i = 0; i < lowerNames.length; i++) {\n    if (lowerNames[i] === lowercaseName) {\n      name = list[i][0];\n      break;\n    }\n  }\n  ArrayPrototypePush(list, [name, value]);","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/fetch/20_headers.js#L158-L194","documentation":"After http-whitespace trimming (normalizeHeaderValue), a header value must not contain LF (0x0A), CR (0x0D), or NUL (0x00) - checkForInvalidValueChars rejects them to prevent header injection and response splitting. Both the mutation path and constructor paths enforce this.","triggerScenarios":"Multi-line values from template literals; values joined with \"\\r\\n\"; user text pasted with newlines; binary data with embedded NUL bytes placed into a header value.","commonSituations":"Putting stack traces, pretty-printed JSON, or free-form user input into a header; CRLF leaking into values from protocol-style string building.","solutions":["Strip or encode newlines: `value.replace(/[\\r\\n\\0]+/g, \" \")` or `encodeURIComponent(value)`","Base64-encode binary or multi-line payloads before placing them in a header","Validate user-supplied values against control characters before setting headers"],"exampleFix":"// before\nheaders.set(\"x-trace\", err.stack ?? \"\"); // contains newlines\n\n// after\nheaders.set(\"x-trace\", encodeURIComponent(err.stack ?? \"\"));","handlingStrategy":"validation","validationCode":"function isValidHeaderValue(value: string): boolean {\n  return !/[\\r\\n\\0]/.test(value);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Strip newlines and NUL from values: value.replace(/[\\r\\n\\0]+/g, ' ')","URL-encode or base64 multi-line payloads before placing them in headers","Treat header values as single-line by construction; never interpolate raw user text"],"tags":["fetch","headers","security","validation"],"backgroundTag":"invalid-header-value","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}