denoland/deno · error · TypeError
ERR_HTTP2_INVALID_ORIGIN
ERR_HTTP2_INVALID_ORIGIN
Error message
HTTP/2 ORIGIN frames require a valid origin
What it means
Http2Session.origin() validates every entry in origins: strings are converted with getURLOrigin(), objects contribute their .origin, and validateString(origin) enforces a string. If the resulting origin is the literal 'null' — the URL parser's opaque-origin marker for schemes like file: or data: — ERR_HTTP2_INVALID_ORIGIN is thrown, since an ORIGIN frame requires concrete serialized origins.
Source
Thrown at ext/node/polyfills/http2.ts:4656
}
if (origins.length === 0) {
return;
}
let arr = "";
let len = 0;
const count = origins.length;
for (let i = 0; i < count; i++) {
let origin = origins[i];
if (typeof origin === "string") {
origin = getURLOrigin(origin);
} else if (origin != null && typeof origin === "object") {
origin = origin.origin;
}
validateString(origin, "origin");
if (origin === "null") {
throw new ERR_HTTP2_INVALID_ORIGIN();
}
arr += `${origin}\0`;
len += origin.length;
}
if (len > kMaxALTSVC) {
throw new ERR_HTTP2_ORIGIN_LENGTH();
}
this[kHandle].origin(arr, count);
}
}
// ClientHttp2Session instances have to wait for the socket to connect after
// they have been created. Various operations such as request() may be used,
// but the actual protocol communication will only occur after the socket
// has been connected.View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Pass absolute https:// URLs (ORIGIN frames are only meaningful on TLS) such as 'https://example.com'
- Filter the list first: origins.filter((o) => o && o !== 'null') on the string forms
- Derive entries from the server's own certificate/hostname configuration, not from request paths
Example fix
// before
session.origin('file:///srv/app', 'https://example.com');
// after
session.origin('https://example.com', 'https://cdn.example.com'); Defensive patterns
Strategy: validation
Validate before calling
const valid = origins.map((o) => typeof o === 'string' ? new URL(o).origin : o?.origin);
if (valid.some((o) => typeof o !== 'string' || o === 'null')) {
throw new TypeError('every origin must be a concrete https origin');
}
session.origin(...origins); Type guard
function areConcreteOrigins(origins) {
return origins.every((o) => {
const org = typeof o === 'string' ? new URL(o).origin : o?.origin;
return typeof org === 'string' && org !== 'null' && org.length > 0;
});
} Prevention
- ORIGIN frames are for TLS servers — only https:// origins are meaningful
- Filter out 'null'/empty origins before submitting
- Non-string, non-null entries fail validateString with ERR_INVALID_ARG_TYPE — normalize first
When it happens
Trigger: session.origin('file:///srv/site'), session.origin({ origin: 'null' }), or any entry whose URL string has no hierarchical http/https origin.
Common situations: Building the origin list from config paths or file:// mounts instead of https:// base URLs; mixing relative paths into the list (those throw ERR_INVALID_URL even earlier via getURLOrigin); opaque origins copied from browser-style URL objects.
Related errors
- ERR_INVALID_URL
- ERR_HTTP2_ALTSVC_INVALID_ORIGIN
- ERR_HTTP2_ORIGIN_LENGTH
- ERR_HTTP2_NO_SOCKET_MANIPULATION
- ERR_HTTP2_SOCKET_UNBOUND
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/f0eb2d561b32b0bb.
Report an issue: GitHub.