Commit 9d8a9adfe83 for nodejs

commit 9d8a9adfe837255ef9e69e19e672f7cce4391fdb
Author: Qingyu Wang <40660121+colinaaa@users.noreply.github.com>
Date:   Sat Nov 7 02:30:31 2026 +0800

    stream: fix pipeTo assert when writer is released during microtask

    pipeTo defers each slow-path write to a microtask so it does not run
    synchronously during enqueue(). A race allows the pipe to shut down and
    release its writer after the write is scheduled but before it runs. The
    deferred write then hits an ERR_INTERNAL_ASSERTION because
    writer[[stream]] is undefined.

    Skip the deferred write when shutdown has already started.

    Fixes: https://github.com/nodejs/node/issues/63732
    Signed-off-by: Qingyu Wang <wangqingyu.c0l1n@bytedance.com>
    Assisted-by: Codex
    PR-URL: https://github.com/nodejs/node/pull/63733
    Reviewed-By: Matteo Collina <matteo.collina@gmail.com>

diff --git a/lib/internal/webstreams/readablestream.js b/lib/internal/webstreams/readablestream.js
index 9ff4670e93b..97bdf261377 100644
--- a/lib/internal/webstreams/readablestream.js
+++ b/lib/internal/webstreams/readablestream.js
@@ -1792,6 +1792,7 @@ function readableStreamPipeTo(
   function forwardChunk() {
     const chunk = pendingChunk;
     pendingChunk = undefined;
+    if (writer[kState].stream === undefined) return;
     writableStreamDefaultWriterWriteWithRequest(writer, chunk, writeTracker);
     pump();
   }
diff --git a/test/parallel/test-webstreams-pipeto-writer-released-race.js b/test/parallel/test-webstreams-pipeto-writer-released-race.js
new file mode 100644
index 00000000000..20e0933bd60
--- /dev/null
+++ b/test/parallel/test-webstreams-pipeto-writer-released-race.js
@@ -0,0 +1,63 @@
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const { ReadableStream, WritableStream } = require('stream/web');
+
+{
+  let sourceController;
+  let destController;
+
+  const source = new ReadableStream({
+    start(controller) {
+      sourceController = controller;
+    },
+  });
+
+  const dest = new WritableStream({
+    start(controller) {
+      destController = controller;
+    },
+    write() {},
+  });
+
+  assert.rejects(
+    source.pipeTo(dest, { preventCancel: true }),
+    { message: 'destination errored' },
+  ).then(common.mustCall());
+
+  setImmediate(common.mustCall(() => {
+    destController.error(new Error('destination errored'));
+    sourceController.enqueue('chunk');
+  }));
+}
+
+{
+  const ac = new AbortController();
+  let sourceController;
+  const chunks = [];
+
+  const source = new ReadableStream({
+    start(controller) {
+      sourceController = controller;
+    },
+  }, { highWaterMark: 0 });
+
+  const dest = new WritableStream({
+    write: common.mustCall((chunk) => {
+      chunks.push(chunk);
+    }),
+  }, { highWaterMark: 1 });
+
+  assert.rejects(
+    source.pipeTo(dest, { signal: ac.signal }),
+    { name: 'AbortError' },
+  ).then(common.mustCall(() => {
+    assert.deepStrictEqual(chunks, ['chunk']);
+  }));
+
+  setImmediate(common.mustCall(() => {
+    sourceController.enqueue('chunk');
+    ac.abort();
+  }));
+}