Repository navigation
aborting stream using the signal does not close the stream when the from generator never finish #47133
Description
Activity
- changed the title
[-]`map` and `forEach` operators need to wait for another item before aborting[/-][+]aborting stream using the signal does not close the stream[/+]on Mar 17, 2023 - changed the title
[-]aborting stream using the signal does not close the stream[/-][+]aborting stream using the signal does not close the stream when the from generator never finish[/+]on Mar 17, 2023 I see that this happens with async generator/iterator when next but not awaited and then
iterator.throw(which is basically what happens in the stream core)// Keep process open setInterval(() => { }, 10000); let resolve; const promise = new Promise(res => resolve = res); async function* neverEnding() { yield 1; await promise; yield 2; yield 3; } async function run() { const iterator = neverEnding(); console.log(await iterator.next()); const res = iterator.next(); console.log(await iterator.throw(new Error('throw error'))); console.log('nothing here') } run() .then(result => console.log('success', result)) .catch(error => console.log('failure', error))
what get logged is:
{ value: 1, done: false }is there something we can do to fix this? or this is JavaScript engine (V8) internal bug?
Looking at the Generator
GeneratorResumeAbruptspecs (that was called fromGenerator.prototype.throwspec) it's not counting forexecuting[[GeneratorState]]which is the current generator state when we calliterator.throwIn the
debuggerthe[[GeneratorState]]is actuallysuspendedwhich is weird because it's not one of the possible values which areundefined,suspendedStart,suspendedYield,executing, orcompleted- addedstreamIssues and PRs related to Node.js streams.Issues and PRs related to Node.js streams.
on Mar 18, 2023 https://tc39.es/ecma262/#sec-properties-of-asyncgenerator-intances are the possible values, and GeneratorState is a slot on sync generators, not async generators.
Thanks @ljharb, so the example of the async generator not throwing is the expected behavior?
I'm not sure what the expected behavior is here tbh.
However, by aborting after 10ms, you're basically making a race condition - I think there's no guarantee that
stream.toArray({ signal: ac.signal })will settle before the 10ms have elapsed.However, by aborting after 10ms, you're basically making a race condition - I think there's no guarantee that
stream.toArray({ signal: ac.signal })will settle before the 10ms have elapsed.the 10ms is just an example it can be 1s as well and the same result,
toArraywill never finishI'm not sure what the expected behavior is here tbh.
Lets say I have this use case:
Taking the first 10 chunks the user wrote, if not written 10 chunks in 10 seconds abortingcode:
const ac = new AbortController(); setTimeout(() => { console.log('10s passed') ac.abort(); }, 10000); process.stdin .map(item => { console.log('item', item) return item.toString(); }, {signal: ac.signal}) .take(10, {signal: ac.signal}) .toArray({signal: ac.signal}) .then(arr => { console.log('success', arr); }) .catch((e) => { console.error('Aborted', e); });
In the current behavior, if you don't type anything and 10s pass, the
Abortedlog won't be logged until you type somethingI don't wanna wait for user input when I close the stream, I expect that when I call
ac.abort()it will abort immediately (can be in the next tick of course)Your
thenandcatch, though, don't take a signal because Promises aren't cancellable.This is why I don't pass them a signal
can I work on this issue?
The problem is if this is even possible, After talking to @giltayar it seems like this can't be fixed as this is how async generator work
WDYT @benjamingr
I was OOO for a while and I'll be abroad until after Passover so my capacity is limited (hence why I didn't weigh in on the transform issue even though I still think the fix is unintuitive).
This just looks like a bug to me where the error is not being propagated correctly, when the stream is destroyed catch should be called with an AbortError even if the generator is being thrown into.
If you remove
addAbortSignalthe behavior is correct because the stream in fact never finishesgithub-actions commented
on Jun 18, 2026 on Jun 18, 2026 – with GitHub ActionsContributorMore actionsThis issue has been marked as stale due to 210 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.- addedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Jun 18, 2026 github-actions commented
on Jul 19, 2026 on Jul 19, 2026 – with GitHub ActionsContributorMore actionsThis issue has been automatically closed after 30 days of inactivity following its stale status (no activity for a total of 240 days).
If this is still relevant, feel free to reopen it or leave a comment with additional details so we can continue the discussion.
Version
v20.0.0-pre (master)
Platform
Darwin MBP 22.3.0 Darwin Kernel Version 22.3.0: Mon Jan 30 20:38:37 PST 2023; root:xnu-8792.81.3~2/RELEASE_ARM64_T6000 arm64
Subsystem
No response
What steps will reproduce the bug?
This fails as the
catchis not calledHow often does it reproduce? Is there a required condition?
always
What is the expected behavior? Why is that the expected behavior?
to close the stream
What do you see instead?
error:
Additional information
If I omit the ``addAbortSignal(ac.signal, stream);
, thestream.destroy` function is not even calledBut when I add the abort signal (
addAbortSignal(ac.signal, stream);) to the original stream it does get called but still, the test fails.this is because we get to this line:
node/lib/internal/streams/from.js
Line 69 in 3a648af
but not to this:
node/lib/internal/streams/from.js
Line 70 in 3a648af