Skip to content

stream: reject writes during WritableStream close - #67058

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
mcollina:webstreams-write-after-close
Nov 2, 2026
Merged

nodejs-github-bot merged 1 commit into
nodejs:mainfrom
mcollina:webstreams-write-after-close

Conversation

@mcollina

@mcollina mcollina commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

WritableStreamDefaultControllerProcessClose clears the controller algorithms while the stream is still 'writable', before the sink close settles. A write in that window reaches the cleared size algorithm and fails the internal assertion in writableStreamDefaultControllerGetChunkSize, which crashes the process instead of rejecting the write:

const ws = new WritableStream({ close() { return new Promise(() => {}); } });
const writer = ws.getWriter();
writer.close();
setImmediate(() => writer.write('x'));
// Error [ERR_INTERNAL_ASSERTION]: This is caused by either a bug in Node.js ...

The same happens when writing to a TransformStream whose flush() is pending. This affects v26.5.1 as well as main.

#57280 handled the 'closed' case (#57272, whatwg/streams#1341). The spec still asserts that the state is not 'writable' there, so the close-in-flight window is a gap in the spec too. This also accepts that state, so the write continues to the closing check and is rejected with a TypeError, as it is once the stream has closed.

Tests are added to test-whatwg-writablestream-close.js for both cases; they fail with the assertion on main.

Refs: #57272
Refs: whatwg/streams#1341


AI generated, reviewed by me

WritableStreamDefaultControllerProcessClose clears the controller
algorithms while the stream is still 'writable', before the sink close
settles. A write in that window, such as writer.write() after
writer.close() while the sink's close() or a TransformStream's flush()
is pending, reached the cleared size algorithm and failed an internal
assertion instead of being rejected as closing. Accept that state in
writableStreamDefaultControllerGetChunkSize so the write is rejected
with a TypeError, as it is once the stream has closed.

Refs: nodejs#57272
Refs: whatwg/streams#1341
Signed-off-by: Matteo Collina <hello@matteocollina.com>
@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 Oct 27, 2026
@codecov

codecov Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.65%. Comparing base (29bd740) to head (199d95b).
⚠️ Report is 257 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #67058      +/-   ##
==========================================
+ Coverage   90.47%   90.65%   +0.18%     
==========================================
  Files         791      797       +6     
  Lines      277245   278270    +1025     
  Branches    53310    53503     +193     
==========================================
+ Hits       250834   252277    +1443     
+ Misses      16811    16385     -426     
- Partials     9600     9608       +8     
Files with missing lines Coverage Δ
lib/internal/webstreams/writablestream.js 99.52% <100.00%> (+<0.01%) ⬆️

... and 135 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@atlowChemi atlowChemi added the request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. label Oct 29, 2026
@github-actions github-actions Bot removed the request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. label Oct 29, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@mcollina mcollina added the commit-queue PRs queued for automated landing through the Commit Queue. label Oct 29, 2026
@nodejs-github-bot nodejs-github-bot added the lacks-second-approval Commit Queue PRs awaiting a second collaborator approval or completion of the required wait. label Oct 29, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 70e1db3 into nodejs:main Nov 2, 2026
80 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 70e1db3

@nodejs-github-bot nodejs-github-bot removed commit-queue PRs queued for automated landing through the Commit Queue. lacks-second-approval Commit Queue PRs awaiting a second collaborator approval or completion of the required wait. labels Nov 2, 2026
aduh95 pushed a commit that referenced this pull request Nov 11, 2026
WritableStreamDefaultControllerProcessClose clears the controller
algorithms while the stream is still 'writable', before the sink close
settles. A write in that window, such as writer.write() after
writer.close() while the sink's close() or a TransformStream's flush()
is pending, reached the cleared size algorithm and failed an internal
assertion instead of being rejected as closing. Accept that state in
writableStreamDefaultControllerGetChunkSize so the write is rejected
with a TypeError, as it is once the stream has closed.

Refs: #57272
Refs: whatwg/streams#1341
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: #67058
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
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.

4 participants