Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stream async iteration breaks when the loop body calls .destroy(null) #23890

Closed
TimothyGu opened this issue Oct 26, 2018 · 4 comments
Closed
Labels
stream Issues and PRs related to the stream subsystem.

Comments

@TimothyGu
Copy link
Member

TimothyGu commented Oct 26, 2018

  • Version: master
  • Platform: all
  • Subsystem: stream
'use strict';

const { Readable } = require('stream');

const r = new Readable({
  objectMode: true,
  read() {
    this.push('asdf');
    this.push('hehe');
    // note: no this.push(null);
    // also reproducible with setTimeout(() => { this.push(null); }, 1000); here.
  }
});

(async () => {
  for await (const a of r) {
    r.destroy(null);
  }
  console.log('done');
})();

Prints

(node:90745) ExperimentalWarning: Readable[Symbol.asyncIterator] is an experimental feature. This feature could change at any time
(node:90745) UnhandledPromiseRejectionWarning: Error [ERR_STREAM_PREMATURE_CLOSE]: Premature close
    at Readable.onclose (internal/streams/end-of-stream.js:64:36)
    at Readable.emit (events.js:182:13)
    at emitCloseNT (internal/streams/destroy.js:59:8)
    at internalTickCallback (internal/process/next_tick.js:72:19)
    at process._tickCallback (internal/process/next_tick.js:47:5)
    at Function.Module.runMain (internal/modules/cjs/loader.js:763:11)
    at startup (internal/bootstrap/node.js:308:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:878:3)
(node:90745) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an asyncfunction without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:90745) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

It seems the ERR_STREAM_PREMATURE_CLOSE is erroneous, as I would expect the loop to terminate without error. Replacing r.destroy(null) with r.destroy(new Error()) would result in a rejected promise with the newly created error, as expected.

/cc @mcollina @devsnek

Refs: #23730 #23785

@TimothyGu TimothyGu added the stream Issues and PRs related to the stream subsystem. label Oct 26, 2018
@TimothyGu
Copy link
Member Author

TimothyGu commented Oct 26, 2018

Notably, the same error may occur with

(async () => {
  for await (const a of r) {
    for await (const b of r) break;
  }
  console.log('done');
})();

as the break calls the return method of the async iterator object, which calls r.destroy(null).

@targos
Copy link
Member

targos commented Oct 26, 2018

What does the spec say about how the iterator should behave in the nested example?

For example, an Array iterator does not seem to be closed in this case:

image

@TimothyGu
Copy link
Member Author

@targos Unfortunately, the spec says nothing about how return methods should function other than that they are for cleaning up resources, and the Web doesn't provide any precedent either. Array iterators don't clean up because they have nothing to clean up.

@TimothyGu TimothyGu changed the title Async iteration breaks when the loop body calls .destroy(null) Stream async iteration breaks when the loop body calls .destroy(null) Oct 26, 2018
@mcollina
Copy link
Member

This was an unintended side effect. I’ll fix it later today.

(Al that lack of prior art is why this is still experimental, sigh).

mcollina added a commit to mcollina/node that referenced this issue Oct 27, 2018
@targos targos closed this as completed in b1e1fe4 Oct 28, 2018
targos pushed a commit that referenced this issue Oct 28, 2018
Fixes: #23890

PR-URL: #23901
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: James M Snell <[email protected]>
targos pushed a commit that referenced this issue Nov 1, 2018
Fixes: #23890

PR-URL: #23901
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: James M Snell <[email protected]>
MylesBorins pushed a commit that referenced this issue Nov 26, 2018
Fixes: #23890

PR-URL: #23901
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: James M Snell <[email protected]>
rvagg pushed a commit that referenced this issue Nov 28, 2018
Fixes: #23890

PR-URL: #23901
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: James M Snell <[email protected]>
MylesBorins pushed a commit that referenced this issue Nov 29, 2018
Fixes: #23890

PR-URL: #23901
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: James M Snell <[email protected]>
achingbrain added a commit to achingbrain/it-to-stream that referenced this issue Jul 2, 2020
Exiting an async iterator in a pipline early causes a `ERR_STREAM_PREMATURE_CLOSE`
to be thrown.

This should be fixed in a future node release: nodejs/node#23890
alanshaw pushed a commit to alanshaw/it-to-stream that referenced this issue Jul 2, 2020
* fix: add buffer require

Future versions of webpack will not bundle node internals so we have to `require` them as they won't be globals any more.

Weirdly `buffer` was already a dep of this module but wasn't used in the actual source 🤷‍♂️

* fix: work around bug in node that makes writable test fail

Exiting an async iterator in a pipline early causes a `ERR_STREAM_PREMATURE_CLOSE`
to be thrown.

This should be fixed in a future node release: nodejs/node#23890
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stream Issues and PRs related to the stream subsystem.
Projects
None yet
Development

No branches or pull requests

3 participants