From 4d5d303a96c8cd17afbe0db7c01cafbaa9668338 Mon Sep 17 00:00:00 2001 From: Daijiro Wachi Date: Sun, 19 Apr 2026 18:18:51 +0900 Subject: [PATCH] stream: ensuring cross-destruction in _duplexify to prevent leaks --- lib/internal/streams/duplexify.js | 2 +- test/parallel/test-stream-duplex-from.js | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/internal/streams/duplexify.js b/lib/internal/streams/duplexify.js index bd51e4fb4f0b7c..0c6701fa271110 100644 --- a/lib/internal/streams/duplexify.js +++ b/lib/internal/streams/duplexify.js @@ -334,7 +334,7 @@ function _duplexify(pair) { eos(r, (err) => { readable = false; if (err) { - destroyer(r, err); + destroyer(w, err); } onfinished(err); }); diff --git a/test/parallel/test-stream-duplex-from.js b/test/parallel/test-stream-duplex-from.js index 631b3586b36191..e12599fed17c14 100644 --- a/test/parallel/test-stream-duplex-from.js +++ b/test/parallel/test-stream-duplex-from.js @@ -401,3 +401,20 @@ function makeATestWritableStream(writeFunc) { assert.strictEqual(d.writable, false); })); } + +// When the readable side errors, the error must propagate to the writable side. +{ + const expectedErr = new Error('readable error'); + const r = new Readable({ read() {} }); + const w = new Writable({ + write(chunk, encoding, callback) { callback(); }, + }); + const d = Duplex.from({ readable: r, writable: w }); + d.on('error', common.mustCall((err) => { + assert.strictEqual(err, expectedErr); + })); + w.on('error', common.mustCall((err) => { + assert.strictEqual(err, expectedErr); + })); + r.destroy(expectedErr); +}