Repository navigation
Conversation
When an async iterator runs on a Readable stream with autoDestroy: false that was destroyed before iteration started, finalize() took the detach branch because autoDestroy was false. This called cleanup(), removing the eos error listener before the stream's asynchronous _destroy completed. When _destroy subsequently finished, emitErrorNT emitted an unhandled 'error' event on a stream with no listeners, crashing the process even though the iteration error was caught by the consumer. Allow already-destroyed streams to take the finalize path without prematurely detaching the error listener. Fixes: nodejs#67418 Signed-off-by: rudy-07 <kanhaiffco2007@gmail.com>
|
Review requested:
|
|
Welcome to Node.js, and thank you for your first contribution! Before review, please take a moment to read:
Please make sure every commit is signed off. For a first pull request, GitHub Actions require collaborator approval and Jenkins CI must be started by a collaborator or triager, so an initial wait is normal. Caution AgentScan found account activity patterns that may be consistent with automation. This is a heuristic, not proof that this pull request was opened by an agent or violates policy. AI-assisted contributions are permitted, but automated tooling must not open pull requests without advance approval, and contributors must personally understand, test, verify, and take responsibility for every submitted change. See the AgentScan analysis, AI use policy, and automation policy for additional context. |
Description
When a
Readablestream withautoDestroy: falseis destroyed with an error before async iteration starts (such as an aborted signal or an explicit.destroy(err)call on a stream with an asynchronous_destroy),createAsyncIteratorsettles the error and callsfinalize().Because
errorwas defined andautoDestroywas false,finalize()took theelsebranch and calledcleanup(), removing theeoserror listener. When_destroyfinished asynchronously,emitErrorNTemitted an'error'event on a stream with zero listeners, crashing the process with an unhandled'error'event despite the consumer wrapping iteration intry / catch.This change checks
stream.destroyedinfinalize(). When the stream is already destroyed, callingdestroyer(stream, null)is a no-op that avoids prematurely detaching the error listener, allowing the pending error to settle cleanly without crashing.Fixes: #67418
Checklist