denoland/deno · error · NodeTypeError
ERR_HTTP2_INVALID_HEADER_VALUE
ERR_HTTP2_INVALID_HEADER_VALUE
Error message
Invalid value "${value}" for header "${name}" What it means
assertValidHeader in http2 compat also checks the value: a header value of undefined or null throws ERR_HTTP2_INVALID_HEADER_VALUE, because HTTP/2 cannot encode a header with no value. Every header set through setHeader/appendHeader/setTrailer/writeHead must carry an actual value (string, number, or array).
Source
Thrown at ext/node/polyfills/internal/http2/compat.js:105
let statusConnectionHeaderWarned = false;
// Defines and implements an API compatibility layer on top of the core
// HTTP/2 implementation, intended to provide an interface that is as
// close as possible to the current require('http') API
const assertValidHeader = hideStackFrames((name, value) => {
if (
name === "" ||
typeof name !== "string" ||
StringPrototypeIncludes(name, " ")
) {
throw new ERR_INVALID_HTTP_TOKEN.HideStackFramesError("Header name", name);
}
if (isPseudoHeader(name)) {
throw new ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED.HideStackFramesError();
}
if (value === undefined || value === null) {
throw new ERR_HTTP2_INVALID_HEADER_VALUE.HideStackFramesError(value, name);
}
if (!isConnectionHeaderAllowed(name, value)) {
connectionHeaderMessageWarn();
}
});
function isPseudoHeader(name) {
switch (name) {
case HTTP2_HEADER_STATUS: // :status
case HTTP2_HEADER_METHOD: // :method
case HTTP2_HEADER_PATH: // :path
case HTTP2_HEADER_AUTHORITY: // :authority
case HTTP2_HEADER_SCHEME: // :scheme
return true;
default:
return false;
}
}View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Skip the header entirely when the value is null or undefined
- Default it when an empty value is meaningful: setHeader(name, value ?? "")
- Filter header maps before writeHead: Object.fromEntries(Object.entries(h).filter(([, v]) => v != null))
Example fix
// before
for (const [k, v] of Object.entries(config.headers)) res.setHeader(k, v); // undefined v throws
// after
for (const [k, v] of Object.entries(config.headers)) {
if (v !== undefined && v !== null) res.setHeader(k, v);
} Defensive patterns
Strategy: validation
Validate before calling
function hasHeaderValue(v) {
return v !== undefined && v !== null;
}
for (const [k, v] of Object.entries(headers)) {
if (hasHeaderValue(v)) res.setHeader(k, v);
} Type guard
function isDefiniteHeaderValue(
v: unknown,
): v is string | number | string[] | number[] {
return v !== undefined && v !== null;
} Try / catch
try {
res.setHeader(k, v);
} catch (err) {
if (err.code === "ERR_HTTP2_INVALID_HEADER_VALUE" && v == null) return; // just skip
throw err;
} Prevention
- Filter null/undefined out of header maps before passing them to h2 APIs
- Use nullish-coalescing defaults for optional headers instead of passing absent values
When it happens
Trigger: res.setHeader("x-optional", undefined) from optional config or destructuring; object-spread headers containing undefined fields passed to writeHead(); trailer values fetched from a Map/lookup that returned null or undefined.
Common situations: Optional feature flags: setHeader("x-deprecated", flags.deprecated) where the field is absent; spreads like { ...commonHeaders, ...overrides } where some keys are undefined; JSON config with null values fed straight into headers.
Related errors
- ERR_INVALID_HTTP_TOKEN
- ERR_INVALID_HTTP_TOKEN
- Invalid header: length must be 2, but is ${header.length}
- Invalid header name: "${name}"
- Invalid header value: "${value}"
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/448ea0a077fdda6a.
Report an issue: GitHub.