denoland/deno · error · TypeError

ERR_HTTP2_ALTSVC_INVALID_ORIGIN

ERR_HTTP2_ALTSVC_INVALID_ORIGIN

Error message

HTTP/2 ALTSVC frames require a valid origin

What it means

In altsvc(alt, originOrStream), when originOrStream is a string it is parsed with getURLOrigin(), which returns new URL(str).origin. URLs that have an opaque/undefined origin (origin === "null" — e.g. file:, data:, or other non-hierarchical schemes) produce ERR_HTTP2_ALTSVC_INVALID_ORIGIN because an ALTSVC frame needs a concrete serialized origin. Note that a string the URL constructor cannot parse at all throws ERR_INVALID_URL earlier instead.

Source

Thrown at ext/node/polyfills/http2.ts:4586

    return this[kServer];
  }

  // Submits an altsvc frame to be sent to the client. `stream` is a
  // numeric Stream ID. origin is a URL string that will be used to get
  // the origin. alt is a string containing the altsvc details. No fancy
  // API is provided for that.
  altsvc(alt, originOrStream) {
    if (this.destroyed) {
      throw new ERR_HTTP2_INVALID_SESSION();
    }

    let stream = 0;
    let origin;

    if (typeof originOrStream === "string") {
      origin = getURLOrigin(originOrStream);
      if (origin === "null") {
        throw new ERR_HTTP2_ALTSVC_INVALID_ORIGIN();
      }
    } else if (typeof originOrStream === "number") {
      if (originOrStream >>> 0 !== originOrStream || originOrStream === 0) {
        throw new ERR_OUT_OF_RANGE(
          "originOrStream",
          `> 0 && < ${2 ** 32}`,
          originOrStream,
        );
      }
      stream = originOrStream;
    } else if (originOrStream !== undefined) {
      // Allow origin to be passed a URL or object with origin property
      if (originOrStream !== null && typeof originOrStream === "object") {
        origin = originOrStream.origin;
      }
      // Note: if originOrStream is an object with an origin property other
      // than a URL, then it is possible that origin will be malformed.
      // We do not verify that here. Users who go that route need to

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Pass an absolute http/https URL such as 'https://example.com:8443' so URL.origin is concrete
  2. Build the origin from the request's authority: `https://${req.authority}` or `https://${req.headers.host}`
  3. If you only mean a stream, pass the numeric stream ID instead of a URL

Example fix

// before
session.altsvc('h2=":8443"', new URL(req.url, 'file:///').href); // origin === 'null'

// after
session.altsvc('h2=":8443"', `https://${clientSocket.remoteAddress}`);
Defensive patterns

Strategy: validation

Validate before calling

const origin = new URL(urlString).origin;
if (origin === 'null') throw new TypeError(`no usable origin in ${urlString}`);
session.altsvc(alt, urlString);

Type guard

function hasConcreteOrigin(urlString) {
  try { return new URL(urlString).origin !== 'null'; } catch { return false; }
}

Prevention

When it happens

Trigger: session.altsvc(alt, 'file:///srv/site'), altsvc(alt, 'data:text/plain,hi'), or any scheme where URL.prototype.origin is the string 'null'.

Common situations: Deriving the origin from req.url (a path like '/foo') instead of the Host header or absolute URL; feeding a config value that lost its scheme ('example.com:8443' is unparseable, 'file://' mounts are 'null'); handling non-HTTP origins in a generic adapter.

Related errors


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