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

  1. Strip or encode newlines: `value.replace(/[\r\n\0]+/g, " ")` or `encodeURIComponent(value)`
  2. Base64-encode binary or multi-line payloads before placing them in a header
  3. 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

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


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)