diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index d69e5aa5b35f5f..63efff40373014 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -798,7 +798,9 @@ Readable.prototype.pipe = function(dest, pipeOpts) { unpipe(); dest.removeListener('error', onerror); if (EE.listenerCount(dest, 'error') === 0) { - if (!dest.destroyed) { + const s = dest._writableState || dest._readableState; + if (s && !s.errorEmitted) { + // User incorrectly emitted 'error' directly on the stream. errorOrDestroy(dest, er); } else { dest.emit('error', er); diff --git a/test/parallel/test-stream2-finish-pipe-error.js b/test/parallel/test-stream2-finish-pipe-error.js new file mode 100644 index 00000000000000..a603e154b98961 --- /dev/null +++ b/test/parallel/test-stream2-finish-pipe-error.js @@ -0,0 +1,20 @@ +'use strict'; +const common = require('../common'); +const stream = require('stream'); + +process.on('uncaughtException', common.mustCall()); + +const r = new stream.Readable(); +r._read = function(size) { + r.push(Buffer.allocUnsafe(size)); +}; + +const w = new stream.Writable(); +w._write = function(data, encoding, cb) { + cb(null); +}; + +r.pipe(w); + +// end() after pipe should cause unhandled exception +w.end(); diff --git a/test/parallel/test-stream2-finish-pipe.js b/test/parallel/test-stream2-finish-pipe.js index 4744093e18f9fa..1cee74063233b2 100644 --- a/test/parallel/test-stream2-finish-pipe.js +++ b/test/parallel/test-stream2-finish-pipe.js @@ -35,7 +35,10 @@ w._write = function(data, encoding, cb) { r.pipe(w); -// This might sound unrealistic, but it happens in net.js. When -// `socket.allowHalfOpen === false`, EOF will cause `.destroySoon()` call which -// ends the writable side of net.Socket. -w.end(); +// end() must be called in nextTick or a WRITE_AFTER_END error occurs. +process.nextTick(() => { + // This might sound unrealistic, but it happens in net.js. When + // socket.allowHalfOpen === false, EOF will cause .destroySoon() call which + // ends the writable side of net.Socket. + w.end(); +});