Skip to content

stream: fix TransformStream race on cancel with pending write#62040

Open
marcopiraccini wants to merge 2 commits intonodejs:mainfrom
marcopiraccini:fix-transform-stream-race
Open

stream: fix TransformStream race on cancel with pending write#62040
marcopiraccini wants to merge 2 commits intonodejs:mainfrom
marcopiraccini:fix-transform-stream-race

Conversation

@marcopiraccini
Copy link
Contributor

Fixes: #62036

  • Fix a race condition in TransformStream where a late writer.write() racing with reader.cancel() could throw an internal TypeError: controller[kState].transformAlgorithm is not a function
  • The race occurs when cancel/abort/close clears the controller's algorithms via transformStreamDefaultControllerClearAlgorithms while a pending write reaches transformStreamDefaultControllerPerformTransform
  • Added a guard in transformStreamDefaultControllerPerformTransform to check if transformAlgorithm is still callable before invoking it

Race sequence

  1. reader.read() releases backpressure
  2. reader.cancel() triggers transformStreamDefaultSourceCancelAlgorithm, which calls transformStreamDefaultControllerClearAlgorithms — sets transformAlgorithm = undefined
  3. writer.write() enters transformStreamDefaultSinkWriteAlgorithm and calls transformStreamDefaultControllerPerformTransform
  4. performTransform tries to invoke transformAlgorithm() which is now undefinedTypeError

Fix

Guard transformStreamDefaultControllerPerformTransform so that if transformAlgorithm has been cleared (stream is shutting down), the write returns silently rather than throwing an internal error. The writable side's existing error handling surfaces the appropriate stream-level error to the caller.

Spec note

The WHATWG streams reference implementation has the same unguarded call in TransformStreamDefaultControllerPerformTransform. The race is latent in the spec but rarely surfaces in browsers due to WebIDL callback wrapping adding an extra promise tick that changes the interleaving order (see whatwg/streams#1296). Node.js hits it consistently because it lacks that extra indirection layer.

Test plan

  • New test test/parallel/test-whatwg-transformstream-cancel-write-race.js reproduces the race.

Signed-off-by: marcopiraccini <marco.piraccini@gmail.com>
@nodejs-github-bot nodejs-github-bot added needs-ci PRs that need a full CI run. web streams labels Feb 28, 2026
@marcopiraccini marcopiraccini marked this pull request as ready for review February 28, 2026 13:15
Signed-off-by: marcopiraccini <marco.piraccini@gmail.com>
Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@mcollina mcollina added the request-ci Add this label to start a Jenkins CI on a PR. label Feb 28, 2026
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Feb 28, 2026
@nodejs-github-bot
Copy link
Collaborator

@codecov
Copy link

codecov bot commented Feb 28, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.62%. Comparing base (35d3bc8) to head (398e700).
⚠️ Report is 5 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #62040      +/-   ##
==========================================
- Coverage   89.65%   89.62%   -0.03%     
==========================================
  Files         676      676              
  Lines      206231   206244      +13     
  Branches    39505    39502       -3     
==========================================
- Hits       184898   184851      -47     
- Misses      13463    13518      +55     
- Partials     7870     7875       +5     
Files with missing lines Coverage Δ
lib/internal/webstreams/transformstream.js 99.57% <100.00%> (+<0.01%) ⬆️

... and 36 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.

@nodejs-github-bot
Copy link
Collaborator

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

stream/web: TransformStream race can throw internal "transformAlgorithm is not a function"

4 participants