v158 · webtransport · receive streams
Migration: what old code sees
Changing the runtime type of every incoming stream sounds breaking — a subclass is how it isn't. Code written against plain ReadableStream keeps passing its instanceof checks and keeps calling the same reader methods, because the subclass inherits them all and adds exactly one thing. This page runs that compatibility matrix on real objects.
Chrome targets WebTransportReceiveStream for Chrome 158 behind the WebTransportReceiveStream flag (--enable-blink-features=WebTransportReceiveStream, or chrome://flags/#enable-experimental-web-platform-features). Rows that need a live instance — which only an established HTTP/3 session can produce — are marked needs live session rather than being simulated.
The compatibility matrix, on this build's real objects
| expression | plain ReadableStream | WebTransportReceiveStream | reading |
|---|---|---|---|
| Press the button. | |||
The feature-detect branches new code should use
const { value: stream } = await incoming.read();
// 1. Old code — unchanged, keeps working on every engine:
if (stream instanceof ReadableStream) { /* still true */ }
// 2. New code, by type (needs the interface in this realm):
if ("WebTransportReceiveStream" in globalThis &&
stream instanceof WebTransportReceiveStream) { /* 158+ */ }
// 3. New code, by capability — survives realm boundaries and Firefox's
// shipped-but-rejecting getStats:
if ("getStats" in stream) {
try {
const stats = await stream.getStats();
} catch (e) {
// Firefox today: NotSupportedError. Treat as "no stats",
// never as "no stream".
}
}
Branch 3 is the robust one: Firefox ships the method but currently rejects with NotSupportedError, so the call must be wrapped — a method existing is not the same as a method working, and a rejection must not take the whole stream path down with it.