denoland/deno · error · TypeError
Invalid header value
Error message
Invalid header value: "${value}" What it means
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.
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
Example fix
// before
headers.set("x-trace", err.stack ?? ""); // contains newlines
// after
headers.set("x-trace", encodeURIComponent(err.stack ?? "")); Defensive patterns
Strategy: validation
Validate before calling
function isValidHeaderValue(value: string): boolean {
return !/[\r\n\0]/.test(value);
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Putting stack traces, pretty-printed JSON, or free-form user input into a header; CRLF leaking into values from protocol-style string building.
Related errors
- ERR_INVALID_HTTP_TOKEN
- ERR_INVALID_HTTP_TOKEN
- Invalid header: length must be 2, but is
- Invalid header name
- Body already consumed.
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/ab08ae6029dd70da.
Report an issue: GitHub.
Appendix: source
Thrown at ext/fetch/20_headers.js:176
return valid;
}
/**
* https://fetch.spec.whatwg.org/#concept-headers-append
* @param {Headers} headers
* @param {string} name
* @param {string} value
*/
function appendHeader(headers, name, value) {
// 1.
value = normalizeHeaderValue(value);
// 2.
if (!checkHeaderNameForHttpTokenCodePoint(name)) {
throw new TypeError(`Invalid header name: "${name}"`);
}
if (!checkForInvalidValueChars(value)) {
throw new TypeError(`Invalid header value: "${value}"`);
}
// 3.
if (headers[_guard] == "immutable") {
throw new TypeError("Cannot change header: headers are immutable");
}
// 7.
const list = headerListFromHeaders(headers);
const lowerNames = ensureLowerNames(headers);
const lowercaseName = byteLowerCase(name);
for (let i = 0; i < lowerNames.length; i++) {
if (lowerNames[i] === lowercaseName) {
name = list[i][0];
break;
}
}
ArrayPrototypePush(list, [name, value]);View on GitHub (pinned to 9ad36f7a2c)