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 object returned by the Node Flight server's pipeToNodeWritable-style API guards pipe() with a hasStartedFlowing flag: one Flight request writes to exactly one writable destination. Calling pipe() a second time on the same request throws, because the request's buffers, drain handlers, and completion state cannot be shared across two streams.

Source

Thrown at packages/react-server-dom-unbundled/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 once per destination: call renderToPipeableStream again for each consumer instead of re-piping the same request
  2. For caching, tee the destination stream (stream.PassThrough piped onward) or serialize the result once and reuse it
  3. In retry logic, guard with your own hasPiped flag and create a fresh request rather than re-invoking pipe

Example fix

// before: same request piped twice
const {pipe} = renderToPipeableStream(<App />, {});
pipe(httpResponse);
pipe(cacheStream); // throws

// after: one request per destination
pipe(renderToPipeableStream(<App />, {}), httpResponse);
pipe(renderToPipeableStream(<App />, {}), cacheStream);

// or tee a single destination
const tee = new PassThrough();
tee.pipe(httpResponse); tee.pipe(cacheStream);
request.pipe(tee);
Defensive patterns

Strategy: validation

Validate before calling

// Wrap pipe() so a second call is your own, clearer error
function pipeOnce(pipeable, destination) {
  if (pipeable._piped) throw new Error('This Flight request was already piped; render a new request per destination.');
  pipeable._piped = true;
  return pipeable.pipe(destination);
}

Try / catch

try { pipeable.pipe(dest); } catch (e) {
  if (e.message.includes('only supports piping to one writable stream')) {
    // recovery: create a fresh render for this destination, do not retry the same request
    return pipeOnce(renderToPipeableStream(element, options), dest);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling request.pipe(writable) twice — e.g. a retry loop that re-pipes on error, piping to both the HTTP response and a cache/tee, or two consumers of the same render result each calling pipe().

Common situations: Implementing render-to-cache by piping the same request to a cache stream and the client; error-handling that retries pipe after a backpressure or socket error; refactoring where pipe is called in two branches that both run.

Related errors


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