denoland/deno · error · TypeError

ERR_HTTP_INVALID_HEADER_VALUE

ERR_HTTP_INVALID_HEADER_VALUE

Error message

Invalid value "${value}" for header "${name}"

What it means

validateHeaderValue() throws ERR_HTTP_INVALID_HEADER_VALUE when the value is exactly undefined. Unlike null (which later serializes as a string), an undefined value means 'key present but no value' - almost always a bug such as reading a missing property - so setting it is rejected instead of silently sending garbage.

Solutions

  1. Default the value: setHeader('x-id', obj.id ?? '') or skip the header when it is undefined.
  2. Fix the source so the property is actually set, or pass null instead of undefined if an empty-ish header is intended.
  3. Add a filter step when bulk-importing header objects: drop entries whose value === undefined.

Example fix

// before
res.setHeader('x-request-id', ctx.requestId); // undefined

// after
if (ctx.requestId !== undefined) res.setHeader('x-request-id', ctx.requestId);
Defensive patterns

Strategy: validation

Validate before calling

function hasHeaderValue(v) {
  return v !== undefined;
}
for (const [k, v] of Object.entries(headerObj)) {
  if (v !== undefined) res.setHeader(k, v); // skip undefined instead of throwing
}

Type guard

type DefinedHeaderRecord = Record<string, string | string[] | null>;
function hasNoUndefinedHeaders(h) {
  return Object.values(h).every((v) => v !== undefined);
}

Prevention

When it happens

Trigger: res.setHeader('x-id', obj.missingProp); writeHead(200, { 'x-tag': undefined }); appendHeader('x-opt', options.feature) where options.feature was never set.

Common situations: Optional config fields forwarded straight into headers; destructuring with a typo'd key; JSON payloads where a field is absent rather than null; TypeScript code where a possibly-undefined field slips past checks.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/f61ad013a4fd1c92. Report an issue: GitHub.

Appendix: source

Thrown at ext/node/polyfills/_http_outgoing.ts:1327

      }
    },
    "OutgoingMessage.prototype._headerNames is deprecated",
    "DEP0066",
  ),
});

export const validateHeaderName = hideStackFrames(
  (name: string, label?: string): void => {
    if (typeof name !== "string" || !name || !checkIsHttpToken(name)) {
      throw new ERR_INVALID_HTTP_TOKEN(label || "Header name", name);
    }
  },
);

export const validateHeaderValue = hideStackFrames(
  (name: string, value: string): void => {
    if (value === undefined) {
      throw new ERR_HTTP_INVALID_HEADER_VALUE(value, name);
    }
    if (checkInvalidHeaderChar(value)) {
      debug('Header "%s" contains invalid characters', name);
      throw new ERR_INVALID_CHAR("header content", name);
    }
  },
);

export function parseUniqueHeadersOption(headers) {
  if (!ArrayIsArray(headers)) {
    return null;
  }

  const unique = new SafeSet();
  const l = headers.length;
  for (let i = 0; i < l; i++) {
    unique.add(StringPrototypeToLowerCase(headers[i]));
  }

View on GitHub (pinned to 9ad36f7a2c)