Intermittent race condition in web streams adapter leads to unhandled rejection.
The issue involves an intermittent race condition in the web streams adapter code, specifically in the error handling path of `Duplex.fromWeb`. The problem manifests as an unhandled rejection when certain timing conditions are met. A reliable reproduction has been provided, but fixing it requires careful handling of asynchronous operations and error paths.
v22.22.0
ubuntu-24.04 (GitHub Actions runner) 20260302.42.1
webstreams
I encountered this as an occasional flake during CI runs, and haven't been able to narrow down the precise sequence of events which cause it, but the root cause in the Node.js code is clear, and suggests an approximate sequence of events (but with some unknown timing requirements):
import { TransformStream } from 'node:stream/web';
import { Duplex } from 'node:stream';
const output = Duplex.fromWeb(new TransformStream());
output.destroy();
output.write('test');
Specifically, it requires the outer error path in this block (line 729) to be invoked: https://github.com/nodejs/node/blob/bb73c10b3261d699ca6910e5a82d7509020e3a3f/lib/internal/webstreams/adapters.js#L719-L730
Though this was observed in Node.js 22.22.0 (and 20.20.0), the same code still exists in the latest version: https://github.com/nodejs/node/blob/9ff27fdb014c21e869966ffcd053c8e2d872d8c3/lib/internal/webstreams/adapters.js#L791-L802
Intermittently reproduces. Presumably a small race window which causes this specific error path.
The error handler expects to receive an array (which it will, if the error comes from SafePromiseAll), which it can filter. It then uses process.nextTick explicitly to prevent unhandled rejections. This suggests that the code is intended to never result in an unhandled rejection which would kill the process.
Process terminates due to an unhandled rejection:
node:internal/webstreams/adapters:706
error = error.filter((e) => e);
^
TypeError: Cannot read properties of null (reading 'filter')
at done (node:internal/webstreams/adapters:706:23)
The same pattern (and p
Claim this issue to let others know you're working on it. You'll earn 20 points when you complete it!