Skip to content

stream: fix pipeTo assert when writer is released during microtask - #63733

Open
colinaaa wants to merge 2 commits into
nodejs:mainfrom
colinaaa:fix-stream-shutdown
Open

stream: fix pipeTo assert when writer is released during microtask#63733
colinaaa wants to merge 2 commits into
nodejs:mainfrom
colinaaa:fix-stream-shutdown

Conversation

@colinaaa

@colinaaa colinaaa commented Jun 3, 2026

Copy link
Copy Markdown

Summary

The deferred write introduced by #61800 wraps the write operation in queueMicrotask(). A race condition exists where the pipe can shutdown and release the writer between when [kChunk] schedules the microtask and when it executes, causing an ERR_INTERNAL_ASSERTION because writer[[stream]] is undefined.

Fix by checking writer[kState].stream === undefined in the deferred microtask before attempting the write. This condition is only true after finalize() has released the writer, precisely targeting the crash without interfering with the spec requirement that already-read chunks are written to a still-writable destination during shutdown.

Fixes: #63732

@nodejs-github-bot nodejs-github-bot added needs-ci PRs that need a full CI run. web streams Issues and PRs related to the Web Streams API. labels Jun 3, 2026
pipeTo defers each slow-path write to a microtask so it does not run
synchronously during enqueue(). A race allows the pipe to shut down and
release its writer after the write is scheduled but before it runs. The
deferred write then hits an ERR_INTERNAL_ASSERTION because
writer[[stream]] is undefined.

Skip the deferred write when shutdown has already started.

Fixes: nodejs#63732
Signed-off-by: Qingyu Wang <[email protected]>
Assisted-by: Codex
The shuttingDown guard added by the previous commit is too broad: it
also skips an already-read chunk while the destination is still
writable. The WHATWG Streams spec requires pipeTo to write such chunks
during shutdown.

Check writer[kState].stream instead. It becomes undefined only after
finalize() releases the writer, which is precisely the assertion case.

Add a regression test that aborts after enqueue() and verifies that the
already-read chunk is written.

Signed-off-by: Qingyu Wang <[email protected]>
Assisted-by: Codex
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-ci PRs that need a full CI run. web streams Issues and PRs related to the Web Streams API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

stream: pipeTo with preventCancel can hit ERR_INTERNAL_ASSERTION if destination errors before deferred write

2 participants