| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
Codecov Report✅ All modified and coverable lines are covered by tests. @@ Coverage Diff @@
## main #5357 +/- ##
==========================================
+ Coverage 93.23% 93.35% +0.11%
==========================================
Files 110 110
Lines 36668 36999 +331
==========================================
+ Hits 34189 34540 +351
+ Misses 2479 2459 -20 ☔ View full report in Codecov by Harness.
|
Sorry, something went wrong.
There was a problem hiding this comment.
I think the bug is elsewhere. That function should not be called.
Sorry, something went wrong.
When a request is aborted mid-stream while its body is being consumed (e.g. body.json()), the abort-signal listener destroys `this.res` in place but does not null it, unlike onResponseError. A chunk arriving afterwards - for example flushed asynchronously by the decompress interceptor - passed the `if (!this.res)` guard in onResponseData and was pushed into the torn-down stream, crashing with "Cannot read properties of null (reading 'push')" instead of the consume promise rejecting with the AbortError. Guard onResponseData against a destroyed response stream so the late chunk is dropped at the handler, before it can reach consumePush. Fixes: nodejs#5356 Signed-off-by: cesarvspr <vinicius_spr@hotmail.com>
|
thx for the heads up @mcollina The abort listener destroys this.res but never nulls it like onResponseError does, so the late decompressor chunk slips past the if (!this.res) check and into consumePush. Moved the guard to onResponseData (drop the chunk if the stream's already destroyed), reverted the readable.js change, added a test. Could also just null this.res in the abort listener to match onResponseError. Went with the guard since it touches less, but easy to switch if you prefer that. |
Sorry, something went wrong.
Fixing the underlying bug is what should be done, not adding another if condition. |
Sorry, something went wrong.
…ta (nodejs#5356) Addresses review: fix the underlying invariant violation rather than adding another guard condition. The codebase contract is that once the response stream is torn down, this.res is null, so the existing `if (!this.res) return` guard in onResponseData drops late chunks. onResponseError already obeys this. The abort-signal listener was the one producer that broke it: it destroyed this.res in place but left the reference set, so a chunk flushed after the abort (e.g. an async decompressor flush) slipped past the guard, reached BodyReadable.push -> consumePush, and crashed on the consume body that consumeFinish had already nulled. Restore the invariant at the producer: null this.res before destroying in the abort listener, mirroring onResponseError. The onResponseData guard reverts to the original bare `!this.res`; the earlier readable.js change is reverted. consumePush is now genuinely unreachable on this path, not guarded.
There was a problem hiding this comment.
lgtm
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
This relates to...
Fixes #5356
Rationale
When a request is aborted mid-stream while its body is being consumed (e.g. body.json() with an AbortSignal timeout), a late chunk could crash the process with TypeError: Cannot read properties of null (reading 'push') instead of the consume promise simply rejecting with the AbortError.
Root cause: the abort-signal listener in lib/api/api-request.js destroys this.res in place but, unlike onResponseError, does not null it. So a chunk that arrives afterwards - for example flushed asynchronously by the decompress interceptor after the abort - passes the existing if (!this.res) guard in onResponseData (the reference is still set, just destroyed) and is pushed into the torn-down BodyReadable, reaching consumePush on a consume whose body has already been nulled.
Changes
Alternative considered
Nulling this.res in the abort-signal listener (to mirror onResponseError) also fixes it and removes the asymmetry directly. I chose the onResponseData guard because it is a smaller surface, uses the public Readable.destroyed, and matches the destroyed-aware request-body guard in api-pipeline.js. Happy to switch to nulling this.res if you prefer the symmetry - the regression test covers both.
Bug Fixes
Breaking Changes and Deprecations
N/A
Status