-
-
Notifications
You must be signed in to change notification settings - Fork 34.9k
Open
Labels
Description
Version
- v22.9.0
- v24.10.0
Platform
Darwin MacBook-Air.local 25.3.0 Darwin Kernel Version 25.3.0: Wed Jan 28 20:49:24 PST 2026; root:xnu-12377.81.4~5/RELEASE_ARM64_T8132 arm64Subsystem
stream/web (TransformStream)
What steps will reproduce the bug?
Run:
import { TransformStream } from 'node:stream/web';
import { setTimeout } from 'node:timers/promises';
const stream = new TransformStream({
transform(chunk, controller) {
controller.enqueue(chunk);
},
});
// Important for reproducing this race consistently in my environment.
await setTimeout(500);
const reader = stream.readable.getReader();
const writer = stream.writable.getWriter();
// Release backpressure.
const pendingRead = reader.read();
// Simulate client disconnect / shutdown.
const pendingCancel = reader.cancel(new Error('client disconnected'));
// Late write racing with cancel.
const pendingLateWrite = writer.write('late-write');
const results = await Promise.allSettled([
pendingRead,
pendingCancel,
pendingLateWrite,
]);
console.log(results);How often does it reproduce? Is there a required condition?
Intermittent race. In my environment, adding await setTimeout(...) before acquiring reader/writer is required for reliable reproduction.
What is the expected behavior? Why is that the expected behavior?
No internal implementation TypeError should leak.
My understanding is that, when shutdown starts concurrently (cancel/abort/close paths), pending or in-flight write() operations are expected to settle coherently with stream shutdown semantics (resolve/reject according to stream state), rather than failing because an internal algorithm slot became non-callable.
What do you see instead?
pendingLateWrite can reject with an internal error:
TypeError: controller[kState].transformAlgorithm is not a function
at transformStreamDefaultControllerPerformTransform (node:internal/webstreams/transformstream:527:37)
at transformStreamDefaultSinkWriteAlgorithm (node:internal/webstreams/transformstream:573:10)
...Additional information
This looks like a race where:
transformStreamDefaultSinkWriteAlgorithmhas accepted/scheduled a write,- shutdown starts (
readable.cancel()/writable.abort()/ close path), transformStreamDefaultControllerClearAlgorithmsclearstransformAlgorithm,- pending write continues and reaches
transformStreamDefaultControllerPerformTransform.
Related discussions:
Reactions are currently unavailable