denoland/deno · error · WebTransportError

e.message

Error message

e.message

What it means

This is the rejection path for WebTransport's connection promise: the underlying connect op failed, and ext/web/webtransport.js maps the op error's message into a WebTransportError (a DOMException subclass) exposed via the session's `ready` promise and any first use of the session (opening streams, datagrams). Common underlying causes: the server does not speak HTTP/3 WebTransport, TLS/certificate failure, or network unreachability. The message text is whatever the transport op reported (shown here as the generic placeholder 'e.message').

Source

Thrown at ext/web/webtransport.js:273

        this.#headerUni = concat(encodeVarint(UNI_WEBTRANSPORT), sessionIdBuf);

        this.#settingsTx = settingsTx;
        this.#settingsRx = settingsRx;
        this.#connect = connect;

        this.#reliability = "supports-unreliable";

        return { conn, sessionId, sessionIdBuf };
      },
    );

    this.#promise = promise;
    this.#datagrams = new WebTransportDatagramDuplexStream(
      illegalConstructorKey,
      promise,
    );
    this.#ready = PromisePrototypeThen(promise, () => undefined, (e) => {
      throw new WebTransportError(e.message);
    });
  }

  getStats() {
    webidl.assertBranded(this, WebTransportPrototype);
    return PromiseResolve({
      bytesSent: 0,
      packetsSent: 0,
      bytesLost: 0,
      packetsLost: 0,
      bytesReceived: 0,
      packetsReceived: 0,
      smoothedRtt: 0,
      rttVariation: 0,
      minRtt: 0,
      estimatedSendRate: null,
      atSendCapacity: false,
    });

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Catch rejections: `await wt.ready.catch((e) => ...)` and inspect e.message / e.source for the real cause.
  2. Verify the endpoint advertises HTTP/3 (Alt-Svc / QUIC on UDP 443) and supports WebTransport.
  3. For local TLS testing, use a trusted cert (mkcert) rather than self-signed, or pass serverCertificateHashes options.
  4. Confirm the URL uses https:// and the correct port, and that UDP/QUIC is not blocked by a firewall.

Example fix

// before
const wt = new WebTransport(url);
await wt.ready; // unhandled WebTransportError

// after
const wt = new WebTransport(url);
try {
  await wt.ready;
} catch (e) {
  console.error("connect failed:", e.message);
  return;
}
Defensive patterns

Strategy: try-catch

Type guard

function isWebTransportError(e) {
  return e instanceof Error && e.name === "WebTransportError";
}

Try / catch

const wt = new WebTransport(url);
try {
  await wt.ready;
} catch (e) {
  if (e.name === "WebTransportError") {
    logAndFallback(e.message); // degrade to fetch/ws fallback or surface to user
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Awaiting `wt.ready` or `wt.datagrams.writable.ready` on a server without WebTransport support; connecting to an HTTP/2-only or plain-TCP endpoint; self-signed certificates; connecting to a host that is down — the constructor succeeds and the failure surfaces asynchronously here.

Common situations: Local dev servers without HTTP/3; proxies/load balancers stripping HTTP/3 or ALT-SVC; expired/self-signed certs in test environments; wrong port (WebTransport runs over QUIC/UDP, typically 443).

Related errors


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