diff --git a/lib/internal/streams/duplexify.js b/lib/internal/streams/duplexify.js index 76d12fdbc44..eb9c0393df0 100644 --- a/lib/internal/streams/duplexify.js +++ b/lib/internal/streams/duplexify.js @@ -116,8 +116,13 @@ module.exports = function duplexify(body, name) { // The async function returned without (fully) consuming the input. // Destroy the duplex so that pipeline propagates destruction // upstream. See https://github.com/nodejs/node/issues/55077. + // Destroy it directly rather than through destroyer(), which + // synthesizes an AbortError for any stream that is not finished. + // The function resolved successfully, so there is no error to + // report, and a duplex outside of a pipeline has nothing listening + // for one. if (!finalized) { - destroyer(d); + d.destroy(); } }, (err) => { diff --git a/test/parallel/test-stream-duplex-from.js b/test/parallel/test-stream-duplex-from.js index a553a90f96e..12f4f237058 100644 --- a/test/parallel/test-stream-duplex-from.js +++ b/test/parallel/test-stream-duplex-from.js @@ -434,3 +434,15 @@ function makeATestWritableStream(writeFunc) { }), ); } + +// Regression for the fix to https://github.com/nodejs/node/issues/55077: +// an AsyncFunction that returns without consuming its input is destroyed, but +// that destruction must not be reported as an error. Outside of a pipeline +// there is nothing listening for one, so an error here is unhandled and takes +// the process down. +{ + const duplex = Duplex.from(async function() { + // Intentionally do not consume the async iterable input. + }); + duplex.on('error', common.mustNotCall()); +}