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

The turbopack server renderer's renderToPipeableStream returns a handle whose pipe() is guarded by a hasStartedFlowing flag: one Flight request can flush to exactly one Node Writable. A second pipe() call throws because the request's row stream cannot be duplicated into two destinations.

Source

Thrown at packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerNode.js:211

    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

  1. Render again with a new renderToPipeableStream call for each destination
  2. Tee via a single PassThrough if multiple consumers need the same bytes
  3. Buffer the render when replayability is required, then write to each destination

Example fix

// before
const {pipe} = renderToPipeableStream(<App />, options);
pipe(res);
pipe(cacheStream); // Error: one writable stream only

// after
const {pipe} = renderToPipeableStream(<App />, options);
pipe(res);
const {pipe: pipe2} = renderToPipeableStream(<App />, options);
pipe2(cacheStream);
Defensive patterns

Strategy: validation

Validate before calling

function createSinglePipeHandle(renderFn) {
  const handle = renderFn();
  let piped = false;
  return {
    pipe(destination) {
      if (piped) throw new Error('Handle already piped; render again');
      piped = true;
      return handle.pipe(destination);
    },
  };
}

Prevention

When it happens

Trigger: Calling pipe() twice on one handle: piping to the HTTP response and then to a second stream (cache writer, duplicate response after retry), or piping again after a destination error.

Common situations: Frameworks that re-pipe after client disconnects; caching middleware trying to tee the RSC payload; SSR error recovery that swaps the destination.

Related errors


AI-assisted analysis of facebook/react@eafeac097b (2026-08-21). Data as JSON: /api/errors/dc0c688b00cdb981. Report an issue: GitHub.