facebook/react · error · Error
React currently only supports piping to one writable stream.
Error message
React currently only supports piping to one writable stream.
What it means
react-server-dom-parcel's renderToPipeableStream returns a pipeable handle guarded by a hasStartedFlowing flag. Once pipe(destination) is called, the Flight request starts flushing rows to that single Node Writable. React throws on any second pipe() call because interleaving the same request's rows into two streams would corrupt the RSC protocol stream.
Source
Thrown at packages/react-server-dom-parcel/src/server/ReactFlightDOMServerNode.js:217
options ? options.identifierPrefix : undefined,
options ? options.temporaryReferences : undefined,
options ? options.startTime : undefined,
__DEV__ && options ? options.environmentName : undefined,
__DEV__ && options ? options.filterStackFrame : undefined,
debugChannelReadable !== undefined,
);
let hasStartedFlowing = false;
startWork(request);
if (debugChannelWritable !== undefined) {
startFlowingDebug(request, debugChannelWritable);
}
if (debugChannelReadable !== undefined) {
startReadingFromDebugChannelReadable(request, debugChannelReadable);
}
return {
pipe<T: Writable>(destination: T): T {
if (hasStartedFlowing) {
throw new Error(
'React currently only supports piping to one writable stream.',
);
}
hasStartedFlowing = true;
startFlowing(request, destination);
destination.on('drain', createDrainHandler(destination, request));
destination.on(
'error',
createCancelHandler(
request,
'The destination stream errored while writing data.',
),
);
// We don't close until the debug channel closes.
if (!__DEV__ || debugChannelReadable === undefined) {
destination.on(
'close',
createCancelHandler(request, 'The destination stream closed early.'),View on GitHub (pinned to eafeac097b)
Solutions
- Call renderToPipeableStream() again to create a new request for each additional destination instead of reusing one handle
- If you need the same output in two places, pipe once into a stream.PassThrough and fan out from that
- When you must replay the payload (caching), buffer the render first (renderToBuffer/string) and then write it to each destination
Example fix
// before
const {pipe} = renderToPipeableStream(<App />, options);
pipe(res);
pipe(cacheStream); // Error: only one writable stream
// after
const {pipe} = renderToPipeableStream(<App />, options);
pipe(res);
const {pipe: pipeToCache} = renderToPipeableStream(<App />, options);
pipeToCache(cacheStream); // separate render per destination Defensive patterns
Strategy: validation
Validate before calling
const {pipe} = renderToPipeableStream(<App />, options);
let piped = false;
function pipeOnce(destination) {
if (piped) {
throw new Error('Stream already piped; create a new render instead.');
}
piped = true;
return pipe(destination);
} Prevention
- Treat the pipeable handle as single-use; never put pipe() inside retry loops
- Create one renderToPipeableStream call per destination
- Wrap framework stream helpers to assert a not-yet-piped invariant before delegating
When it happens
Trigger: Calling pipe() twice on the same handle returned by renderToPipeableStream: piping once to the http.ServerResponse and again to a cache write-stream, or re-piping to a fresh response after a client disconnect/abort retry.
Common situations: SSR error handlers that swap destinations mid-stream; middleware wanting to tee the RSC payload for logging or edge caching; retry loops that call pipe(res) again after backpressure or a socket error.
Related errors
- React currently only supports piping to one writable stream.
- React currently only supports piping to one writable stream.
- react-dom/server is not supported in React Server Components
- Server Functions cannot be called during initial render. Thi
- Use react-server-dom-parcel/client instead.
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/e2998ba98eb47865.
Report an issue: GitHub.