| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
consumeStart() is a free function, invoked as consumeStart(stream[kConsume]) from
the queueMicrotask() above it, so there is no `this` inside it. The endEmitted
branch nevertheless read this[kConsume] and this._readableState.encoding:
TypeError: Cannot read properties of undefined (reading 'Symbol(kConsume)')
at consumeStart (lib/api/readable.js:490:20)
at lib/api/readable.js:450:9
at node:internal/process/task_queues:149:7
The two lines are identical to the ones in the on('end') callback just below,
where they are correct because the emitter supplies the stream as the receiver.
Because the throw happens on a microtask rather than in the promise chain, the
caller cannot catch it: awaiting the consume inside try/catch still ends the
process. Draining a body and then deciding to read it is enough to get there,
which the added test does with an empty body.
The early return is part of the fix rather than tidying: consumeEnd() clears
consume.stream, and the resume() a few lines down would then dereference null.
Signed-off-by: marko1olo <marko1olo@users.noreply.github.com>
Codecov Report✅ All modified and coverable lines are covered by tests. @@ Coverage Diff @@
## main #5617 +/- ##
========================================
Coverage 93.50% 93.51%
========================================
Files 110 110
Lines 38303 38429 +126
========================================
+ Hits 35816 35935 +119
- Misses 2487 2494 +7 ☔ View full report in Codecov by Harness.
|
Sorry, something went wrong.
There was a problem hiding this comment.
lgtm
Sorry, something went wrong.
Bumps [undici](https://github.com/nodejs/undici) from 8.5.0 to 8.10.0. Release notes *Sourced from [undici's releases](https://github.com/nodejs/undici/releases).* > v8.10.0 > ------- > > What's Changed > -------------- > > * feat: namespace h2 options by [`@metcoder95`](https://github.com/metcoder95) in [nodejs/undici#5498](https://redirect.github.com/nodejs/undici/pull/5498) > * test: update WPT expectations by [`@mcollina`](https://github.com/mcollina) in [nodejs/undici#5587](https://redirect.github.com/nodejs/undici/pull/5587) > * test: add cache/dedupe + dns re-dispatch integration tests by [`@GiHoon1123`](https://github.com/GiHoon1123) in [nodejs/undici#5535](https://redirect.github.com/nodejs/undici/pull/5535) > * fix(websocket): support process.unref by [`@mcollina`](https://github.com/mcollina) in [nodejs/undici#5578](https://redirect.github.com/nodejs/undici/pull/5578) > * fix(h2): ensure every request settles by [`@mcollina`](https://github.com/mcollina) in [nodejs/undici#5603](https://redirect.github.com/nodejs/undici/pull/5603) > * fix(readable): consume a body whose end has already been emitted by [`@marko1olo`](https://github.com/marko1olo) in [nodejs/undici#5617](https://redirect.github.com/nodejs/undici/pull/5617) > * fix(retry): skip the content-length checkpoint for HEAD and for a 206 without content-range by [`@marko1olo`](https://github.com/marko1olo) in [nodejs/undici#5610](https://redirect.github.com/nodejs/undici/pull/5610) > * fix: revert idle socket validation to setTimeout(0) to prevent stall on idle event loop by [`@marceli1404`](https://github.com/marceli1404) in [nodejs/undici#5606](https://redirect.github.com/nodejs/undici/pull/5606) > * fix(env-http-proxy-agent): match bare IPv6 addresses in no\_proxy by [`@marko1olo`](https://github.com/marko1olo) in [nodejs/undici#5623](https://redirect.github.com/nodejs/undici/pull/5623) > * test: handle aggregate balanced pool errors by [`@marko1olo`](https://github.com/marko1olo) in [nodejs/undici#5377](https://redirect.github.com/nodejs/undici/pull/5377) > * fix(readable): keep body bytes that arrive after setEncoding() by [`@mcollina`](https://github.com/mcollina) in [nodejs/undici#5620](https://redirect.github.com/nodejs/undici/pull/5620) > * fix(socks5): evict unused origin pools by [`@Kkartik14`](https://github.com/Kkartik14) in [nodejs/undici#5595](https://redirect.github.com/nodejs/undici/pull/5595) > * fix: skip deduplication for upgrade requests by [`@Ram-blip`](https://github.com/Ram-blip) in [nodejs/undici#5593](https://redirect.github.com/nodejs/undici/pull/5593) > * fix(retry): forward informational responses by [`@mcollina`](https://github.com/mcollina) in [nodejs/undici#5625](https://redirect.github.com/nodejs/undici/pull/5625) > * fix(mock): non-string path matchers under ignoreTrailingSlash, and DataView reply bodies by [`@marko1olo`](https://github.com/marko1olo) in [nodejs/undici#5619](https://redirect.github.com/nodejs/undici/pull/5619) > * fix(interceptors): cache() and deduplicate() silently inert on Client/Pool without opts.origin by [`@marko1olo`](https://github.com/marko1olo) in [nodejs/undici#5628](https://redirect.github.com/nodejs/undici/pull/5628) > * build(deps): bump ossf/scorecard-action from 2.4.3 to 2.4.4 by [`@dependabot`](https://github.com/dependabot)[bot] in [nodejs/undici#5633](https://redirect.github.com/nodejs/undici/pull/5633) > * build(deps): bump github/codeql-action/init from 4.36.2 to 4.37.3 by [`@dependabot`](https://github.com/dependabot)[bot] in [nodejs/undici#5634](https://redirect.github.com/nodejs/undici/pull/5634) > * build(deps): bump actions/setup-node from 6.4.0 to 7.0.0 by [`@dependabot`](https://github.com/dependabot)[bot] in [nodejs/undici#5636](https://redirect.github.com/nodejs/undici/pull/5636) > * fix(mock): emit request body lifecycle hooks by [`@marko1olo`](https://github.com/marko1olo) in [nodejs/undici#5367](https://redirect.github.com/nodejs/undici/pull/5367) > * fix(h2): detach upgrade close handler after GOAWAY by [`@pacocartones`](https://github.com/pacocartones) in [nodejs/undici#5641](https://redirect.github.com/nodejs/undici/pull/5641) > * fix: retry refused HTTP/2 streams by [`@mcollina`](https://github.com/mcollina) in [nodejs/undici#5598](https://redirect.github.com/nodejs/undici/pull/5598) > * fix: preserve DNS origin hostname on sockets by [`@cyphercodes`](https://github.com/cyphercodes) in [nodejs/undici#5577](https://redirect.github.com/nodejs/undici/pull/5577) > > New Contributors > ---------------- > > * [`@marceli1404`](https://github.com/marceli1404) made their first contribution in [nodejs/undici#5606](https://redirect.github.com/nodejs/undici/pull/5606) > * [`@Kkartik14`](https://github.com/Kkartik14) made their first contribution in [nodejs/undici#5595](https://redirect.github.com/nodejs/undici/pull/5595) > * [`@pacocartones`](https://github.com/pacocartones) made their first contribution in [nodejs/undici#5641](https://redirect.github.com/nodejs/undici/pull/5641) > * [`@cyphercodes`](https://github.com/cyphercodes) made their first contribution in [nodejs/undici#5577](https://redirect.github.com/nodejs/undici/pull/5577) > > **Full Changelog**: <nodejs/undici@v8.9.0...v8.10.0> > > v8.9.0 > ------ > > ⚠️ Security fixes > ----------------- > > ### High severity > > * [GHSA-4cwx-7wf7-3272](GHSA-4cwx-7wf7-3272): malformed qualified `private` Cache-Control directives could cause cross-user information disclosure in shared caches or a parse-time crash. The cache parser now treats empty qualified directives conservatively and safely handles mixed qualified and unqualified directives. Fixed by [4fe5bc5f](nodejs/undici@4fe5bc5) with regression coverage in [9f09b49a](nodejs/undici@9f09b49). > > ### Medium severity > > * [GHSA-m8rv-5g2x-5cg5](GHSA-m8rv-5g2x-5cg5): a malicious `type` property on a duck-typed blob-like HTTP/1.1 request body could inject CRLF sequences into the generated `content-type` header. Undici now coerces and validates the value before adding it to the request. Fixed by [7d3cf924](nodejs/undici@7d3cf92). > * [GHSA-jr45-8vmc-qm54](GHSA-jr45-8vmc-qm54): optional whitespace around `=` in qualified `no-cache` and `private` directives could bypass shared-cache restrictions and disclose authenticated data across users. Cache-Control parsing now normalizes these forms and applies conservative cache decisions. Fixed by [c601fff1](nodejs/undici@c601fff). > * [GHSA-8xcm-r25x-g524](GHSA-8xcm-r25x-g524): the retry interceptor could expose a stale `Content-Length` after resuming a partial response, potentially causing downstream response desynchronization, hangs, or corruption. Undici now rejects partial responses whose `Content-Length` is inconsistent with `Content-Range`. Fixed by [e11a68ed](nodejs/undici@e11a68e), with corrected fixtures in [2b3f7493](nodejs/undici@2b3f749). > * [GHSA-v3r7-h72x-cjcm](GHSA-v3r7-h72x-cjcm): unsanitized `domain` and `unparsed` values passed to `setCookie()` could inject cookie attributes. Undici now validates cookie domains, paths, and unparsed attributes more strictly. Fixed by [10d93fc3](nodejs/undici@10d93fc). > > Additional hardening > -------------------- ... (truncated) Commits * [`c8d80e6`](nodejs/undici@c8d80e6) Bumped v8.10.0 ([#5644](https://redirect.github.com/nodejs/undici/issues/5644)) * [`66923b4`](nodejs/undici@66923b4) fix: preserve DNS origin hostname on sockets ([#5577](https://redirect.github.com/nodejs/undici/issues/5577)) * [`3926499`](nodejs/undici@3926499) fix: retry refused HTTP/2 streams ([#5598](https://redirect.github.com/nodejs/undici/issues/5598)) * [`73d6e9e`](nodejs/undici@73d6e9e) fix(h2): detach upgrade close handler after GOAWAY ([#5641](https://redirect.github.com/nodejs/undici/issues/5641)) * [`b111adb`](nodejs/undici@b111adb) fix(mock): emit request body lifecycle hooks ([#5367](https://redirect.github.com/nodejs/undici/issues/5367)) * [`ae4a3e3`](nodejs/undici@ae4a3e3) build(deps): bump actions/setup-node from 6.4.0 to 7.0.0 ([#5636](https://redirect.github.com/nodejs/undici/issues/5636)) * [`ec3fbf1`](nodejs/undici@ec3fbf1) build(deps): bump github/codeql-action/init from 4.36.2 to 4.37.3 ([#5634](https://redirect.github.com/nodejs/undici/issues/5634)) * [`2151720`](nodejs/undici@2151720) build(deps): bump ossf/scorecard-action from 2.4.3 to 2.4.4 ([#5633](https://redirect.github.com/nodejs/undici/issues/5633)) * [`b96a116`](nodejs/undici@b96a116) fix(interceptors): allow interceptors without opts.origin ([#5628](https://redirect.github.com/nodejs/undici/issues/5628)) * [`a18ef2d`](nodejs/undici@a18ef2d) fix(mock): non-string path matchers under ignoreTrailingSlash, and DataView r... * Additional commits viewable in [compare view](nodejs/undici@v8.5.0...v8.10.0) [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- Dependabot commands and options You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/ArcadeData/arcadedb/network/alerts).
…p ci] Bumps [undici](https://github.com/nodejs/undici) from 8.5.0 to 8.10.0. Release notes *Sourced from [undici's releases](https://github.com/nodejs/undici/releases).* > v8.10.0 > ------- > > What's Changed > -------------- > > * feat: namespace h2 options by [`@metcoder95`](https://github.com/metcoder95) in [nodejs/undici#5498](https://redirect.github.com/nodejs/undici/pull/5498) > * test: update WPT expectations by [`@mcollina`](https://github.com/mcollina) in [nodejs/undici#5587](https://redirect.github.com/nodejs/undici/pull/5587) > * test: add cache/dedupe + dns re-dispatch integration tests by [`@GiHoon1123`](https://github.com/GiHoon1123) in [nodejs/undici#5535](https://redirect.github.com/nodejs/undici/pull/5535) > * fix(websocket): support process.unref by [`@mcollina`](https://github.com/mcollina) in [nodejs/undici#5578](https://redirect.github.com/nodejs/undici/pull/5578) > * fix(h2): ensure every request settles by [`@mcollina`](https://github.com/mcollina) in [nodejs/undici#5603](https://redirect.github.com/nodejs/undici/pull/5603) > * fix(readable): consume a body whose end has already been emitted by [`@marko1olo`](https://github.com/marko1olo) in [nodejs/undici#5617](https://redirect.github.com/nodejs/undici/pull/5617) > * fix(retry): skip the content-length checkpoint for HEAD and for a 206 without content-range by [`@marko1olo`](https://github.com/marko1olo) in [nodejs/undici#5610](https://redirect.github.com/nodejs/undici/pull/5610) > * fix: revert idle socket validation to setTimeout(0) to prevent stall on idle event loop by [`@marceli1404`](https://github.com/marceli1404) in [nodejs/undici#5606](https://redirect.github.com/nodejs/undici/pull/5606) > * fix(env-http-proxy-agent): match bare IPv6 addresses in no\_proxy by [`@marko1olo`](https://github.com/marko1olo) in [nodejs/undici#5623](https://redirect.github.com/nodejs/undici/pull/5623) > * test: handle aggregate balanced pool errors by [`@marko1olo`](https://github.com/marko1olo) in [nodejs/undici#5377](https://redirect.github.com/nodejs/undici/pull/5377) > * fix(readable): keep body bytes that arrive after setEncoding() by [`@mcollina`](https://github.com/mcollina) in [nodejs/undici#5620](https://redirect.github.com/nodejs/undici/pull/5620) > * fix(socks5): evict unused origin pools by [`@Kkartik14`](https://github.com/Kkartik14) in [nodejs/undici#5595](https://redirect.github.com/nodejs/undici/pull/5595) > * fix: skip deduplication for upgrade requests by [`@Ram-blip`](https://github.com/Ram-blip) in [nodejs/undici#5593](https://redirect.github.com/nodejs/undici/pull/5593) > * fix(retry): forward informational responses by [`@mcollina`](https://github.com/mcollina) in [nodejs/undici#5625](https://redirect.github.com/nodejs/undici/pull/5625) > * fix(mock): non-string path matchers under ignoreTrailingSlash, and DataView reply bodies by [`@marko1olo`](https://github.com/marko1olo) in [nodejs/undici#5619](https://redirect.github.com/nodejs/undici/pull/5619) > * fix(interceptors): cache() and deduplicate() silently inert on Client/Pool without opts.origin by [`@marko1olo`](https://github.com/marko1olo) in [nodejs/undici#5628](https://redirect.github.com/nodejs/undici/pull/5628) > * build(deps): bump ossf/scorecard-action from 2.4.3 to 2.4.4 by [`@dependabot`](https://github.com/dependabot)[bot] in [nodejs/undici#5633](https://redirect.github.com/nodejs/undici/pull/5633) > * build(deps): bump github/codeql-action/init from 4.36.2 to 4.37.3 by [`@dependabot`](https://github.com/dependabot)[bot] in [nodejs/undici#5634](https://redirect.github.com/nodejs/undici/pull/5634) > * build(deps): bump actions/setup-node from 6.4.0 to 7.0.0 by [`@dependabot`](https://github.com/dependabot)[bot] in [nodejs/undici#5636](https://redirect.github.com/nodejs/undici/pull/5636) > * fix(mock): emit request body lifecycle hooks by [`@marko1olo`](https://github.com/marko1olo) in [nodejs/undici#5367](https://redirect.github.com/nodejs/undici/pull/5367) > * fix(h2): detach upgrade close handler after GOAWAY by [`@pacocartones`](https://github.com/pacocartones) in [nodejs/undici#5641](https://redirect.github.com/nodejs/undici/pull/5641) > * fix: retry refused HTTP/2 streams by [`@mcollina`](https://github.com/mcollina) in [nodejs/undici#5598](https://redirect.github.com/nodejs/undici/pull/5598) > * fix: preserve DNS origin hostname on sockets by [`@cyphercodes`](https://github.com/cyphercodes) in [nodejs/undici#5577](https://redirect.github.com/nodejs/undici/pull/5577) > > New Contributors > ---------------- > > * [`@marceli1404`](https://github.com/marceli1404) made their first contribution in [nodejs/undici#5606](https://redirect.github.com/nodejs/undici/pull/5606) > * [`@Kkartik14`](https://github.com/Kkartik14) made their first contribution in [nodejs/undici#5595](https://redirect.github.com/nodejs/undici/pull/5595) > * [`@pacocartones`](https://github.com/pacocartones) made their first contribution in [nodejs/undici#5641](https://redirect.github.com/nodejs/undici/pull/5641) > * [`@cyphercodes`](https://github.com/cyphercodes) made their first contribution in [nodejs/undici#5577](https://redirect.github.com/nodejs/undici/pull/5577) > > **Full Changelog**: <nodejs/undici@v8.9.0...v8.10.0> > > v8.9.0 > ------ > > ⚠️ Security fixes > ----------------- > > ### High severity > > * [GHSA-4cwx-7wf7-3272](GHSA-4cwx-7wf7-3272): malformed qualified `private` Cache-Control directives could cause cross-user information disclosure in shared caches or a parse-time crash. The cache parser now treats empty qualified directives conservatively and safely handles mixed qualified and unqualified directives. Fixed by [4fe5bc5f](nodejs/undici@4fe5bc5) with regression coverage in [9f09b49a](nodejs/undici@9f09b49). > > ### Medium severity > > * [GHSA-m8rv-5g2x-5cg5](GHSA-m8rv-5g2x-5cg5): a malicious `type` property on a duck-typed blob-like HTTP/1.1 request body could inject CRLF sequences into the generated `content-type` header. Undici now coerces and validates the value before adding it to the request. Fixed by [7d3cf924](nodejs/undici@7d3cf92). > * [GHSA-jr45-8vmc-qm54](GHSA-jr45-8vmc-qm54): optional whitespace around `=` in qualified `no-cache` and `private` directives could bypass shared-cache restrictions and disclose authenticated data across users. Cache-Control parsing now normalizes these forms and applies conservative cache decisions. Fixed by [c601fff1](nodejs/undici@c601fff). > * [GHSA-8xcm-r25x-g524](GHSA-8xcm-r25x-g524): the retry interceptor could expose a stale `Content-Length` after resuming a partial response, potentially causing downstream response desynchronization, hangs, or corruption. Undici now rejects partial responses whose `Content-Length` is inconsistent with `Content-Range`. Fixed by [e11a68ed](nodejs/undici@e11a68e), with corrected fixtures in [2b3f7493](nodejs/undici@2b3f749). > * [GHSA-v3r7-h72x-cjcm](GHSA-v3r7-h72x-cjcm): unsanitized `domain` and `unparsed` values passed to `setCookie()` could inject cookie attributes. Undici now validates cookie domains, paths, and unparsed attributes more strictly. Fixed by [10d93fc3](nodejs/undici@10d93fc). > > Additional hardening > -------------------- ... (truncated) Commits * [`c8d80e6`](nodejs/undici@c8d80e6) Bumped v8.10.0 ([#5644](https://redirect.github.com/nodejs/undici/issues/5644)) * [`66923b4`](nodejs/undici@66923b4) fix: preserve DNS origin hostname on sockets ([#5577](https://redirect.github.com/nodejs/undici/issues/5577)) * [`3926499`](nodejs/undici@3926499) fix: retry refused HTTP/2 streams ([#5598](https://redirect.github.com/nodejs/undici/issues/5598)) * [`73d6e9e`](nodejs/undici@73d6e9e) fix(h2): detach upgrade close handler after GOAWAY ([#5641](https://redirect.github.com/nodejs/undici/issues/5641)) * [`b111adb`](nodejs/undici@b111adb) fix(mock): emit request body lifecycle hooks ([#5367](https://redirect.github.com/nodejs/undici/issues/5367)) * [`ae4a3e3`](nodejs/undici@ae4a3e3) build(deps): bump actions/setup-node from 6.4.0 to 7.0.0 ([#5636](https://redirect.github.com/nodejs/undici/issues/5636)) * [`ec3fbf1`](nodejs/undici@ec3fbf1) build(deps): bump github/codeql-action/init from 4.36.2 to 4.37.3 ([#5634](https://redirect.github.com/nodejs/undici/issues/5634)) * [`2151720`](nodejs/undici@2151720) build(deps): bump ossf/scorecard-action from 2.4.3 to 2.4.4 ([#5633](https://redirect.github.com/nodejs/undici/issues/5633)) * [`b96a116`](nodejs/undici@b96a116) fix(interceptors): allow interceptors without opts.origin ([#5628](https://redirect.github.com/nodejs/undici/issues/5628)) * [`a18ef2d`](nodejs/undici@a18ef2d) fix(mock): non-string path matchers under ignoreTrailingSlash, and DataView r... * Additional commits viewable in [compare view](nodejs/undici@v8.5.0...v8.10.0) [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- Dependabot commands and options You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/ArcadeData/arcadedb/network/alerts).
| Back | FazBrowse Home | New Git URL |
Fixes #5614.
consumeStart() is a free function, called as consumeStart(stream[kConsume]) from the queueMicrotask() above it, so this is undefined inside it under 'use strict'. The state.endEmitted branch read this[kConsume] anyway:
TypeError: Cannot read properties of undefined (reading 'Symbol(kConsume)') at consumeStart (lib/api/readable.js:490:20) at lib/api/readable.js:450:9 at node:internal/process/task_queues:149:7The two lines are character-for-character the same as the ones in the on('end') callback immediately below, which is what makes it easy to read past — those work, because the emitter invokes the callback with the stream as its receiver.
The part that makes it worth fixing rather than tidying is that the caller cannot catch it. The throw happens on a microtask rather than in the promise chain, so awaiting the consume inside try/catch still takes the process down. Draining a body and then deciding to read it after all is enough to reach it.
On the early return
Correcting only the receiver moves the crash rather than removing it:
TypeError: Cannot read properties of null (reading 'resume') at consumeStart (lib/api/readable.js:497:18)consumeEnd() sets consume.stream to null, and the consume.stream.resume() a few lines down then dereferences it — reachable only once the branch above stops throwing first. So the return is part of the fix.
Tests
One case added to test/readable.js: an empty body, drained, then consumed. Without the change the test runner reports it as an uncaught exception rather than a failed assertion, which is the same shape as the bug:
test/readable.js 11/11 and test/client-request.js 48/48 with the change; eslint clean.
Possible drawbacks
The endEmitted path is reached by consuming a body after 'end', and I have only exercised it with an empty body and with a drained 204 over a real request. A body that emitted data first is disturbed and rejects with TypeError: unusable before reaching this code, both before and after — I checked that separately so the change is not masking it.
Node 24 on Windows only; I have not run the other matrix cells locally. I did not run npm run test:typescript, which fails on clean main in Git Bash for an unrelated reason (the script relies on shell glob expansion for types/*.d.ts).