Skip to content

Commit

Permalink
doc: clarify stream errors while reading and writing
Browse files Browse the repository at this point in the history
Errors should be propagated through destroy(err). Anything else
is basically undefined behaviour.

PR-URL: #29653
Refs: #29584
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
  • Loading branch information
ronag authored and Trott committed Sep 27, 2019
1 parent ccb524f commit 7223ce2
Showing 1 changed file with 18 additions and 18 deletions.
36 changes: 18 additions & 18 deletions doc/api/stream.md
Original file line number Diff line number Diff line change
Expand Up @@ -1879,13 +1879,11 @@ or write buffered data before a stream ends.

#### Errors While Writing

It is recommended that errors occurring during the processing of the
`writable._write()` and `writable._writev()` methods are reported by invoking
the callback and passing the error as the first argument. This will cause an
`'error'` event to be emitted by the `Writable`. Throwing an `Error` from within
`writable._write()` can result in unexpected and inconsistent behavior depending
on how the stream is being used. Using the callback ensures consistent and
predictable handling of errors.
Errors occurring during the processing of the [`writable._write()`][],
[`writable._writev()`][] and [`writable._final()`] methods must be propagated
by invoking the callback and passing the error as the first argument.
Throwing an `Error` from within these methods or manually emitting an `'error'`
event results in undefined behavior.

If a `Readable` stream pipes into a `Writable` stream when `Writable` emits an
error, the `Readable` stream will be unpiped.
Expand Down Expand Up @@ -2159,24 +2157,22 @@ buffer. See [`readable.push('')`][] for more information.

#### Errors While Reading

It is recommended that errors occurring during the processing of the
`readable._read()` method are emitted using the `'error'` event rather than
being thrown. Throwing an `Error` from within `readable._read()` can result in
unexpected and inconsistent behavior depending on whether the stream is
operating in flowing or paused mode. Using the `'error'` event ensures
consistent and predictable handling of errors.
Errors occurring during processing of the [`readable._read()`][] must be
propagated through the [`readable.destroy(err)`][readable-_destroy] method.
Throwing an `Error` from within [`readable._read()`][] or manually emitting an
`'error'` event results in undefined behavior.

<!-- eslint-disable no-useless-return -->
```js
const { Readable } = require('stream');

const myReadable = new Readable({
read(size) {
if (checkSomeErrorCondition()) {
process.nextTick(() => this.emit('error', err));
return;
const err = checkSomeErrorCondition();
if (err) {
this.destroy(err);
} else {
// Do some work.
}
// Do some work.
}
});
```
Expand Down Expand Up @@ -2776,6 +2772,7 @@ contain multi-byte characters.
[`process.stderr`]: process.html#process_process_stderr
[`process.stdin`]: process.html#process_process_stdin
[`process.stdout`]: process.html#process_process_stdout
[`readable._read()`]: #stream_readable_read_size_1
[`readable.push('')`]: #stream_readable_push
[`readable.setEncoding()`]: #stream_readable_setencoding_encoding
[`stream.Readable.from()`]: #stream_stream_readable_from_iterable_options
Expand All @@ -2786,6 +2783,9 @@ contain multi-byte characters.
[`stream.uncork()`]: #stream_writable_uncork
[`stream.unpipe()`]: #stream_readable_unpipe_destination
[`stream.wrap()`]: #stream_readable_wrap_stream
[`writable._final()`]: #stream_writable_final_callback
[`writable._write()`]: #stream_writable_write_chunk_encoding_callback_1
[`writable._writev()`]: #stream_writable_writev_chunks_callback
[`writable.cork()`]: #stream_writable_cork
[`writable.end()`]: #stream_writable_end_chunk_encoding_callback
[`writable.uncork()`]: #stream_writable_uncork
Expand Down

2 comments on commit 7223ce2

@gramakri
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ronag @Trott the docs here are a bit confusing. For readable stream, it says "Errors occurring during processing of the readable._read() must be propagated through the readable.destroy(err) method. Throwing an Error from within readable._read() or manually emitting an 'error' event results in undefined behavior."

This does not seem right because if we call destroy(err) directly, this bypasses any autoDestroy flag set in the stream. In fact, many of the examples in the wild seems to emit('error', e) inside _read. Is all that code incorrect or are the docs wrong? If the docs are correct, what is the correct way to signal errors for readable streams with autoDestroy set to false?

@ronag
Copy link
Member Author

@ronag ronag commented on 7223ce2 Dec 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should always call destroy even if autoDestroy false.

Please sign in to comment.