{"record":{"id":"4827f0e7bdba52a6","repo":"facebook/react","slug":"417","errorCode":"417","errorMessage":"React currently only supports piping to one writable stream.","messagePattern":"React currently only supports piping to one writable stream\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-dom/src/server/ReactDOMFizzServerNode.js","lineNumber":144,"sourceCode":"    options ? options.onAllReady : undefined,\n    options ? options.onShellReady : undefined,\n    options ? options.onShellError : undefined,\n    undefined,\n    options ? options.formState : undefined,\n  );\n}\n\nfunction renderToPipeableStream(\n  children: ReactNodeList,\n  options?: Options,\n): PipeableStream {\n  const request = createRequestImpl(children, options);\n  let hasStartedFlowing = false;\n  startWork(request);\n  return {\n    pipe<T: Writable>(destination: T): T {\n      if (hasStartedFlowing) {\n        throw new Error(\n          'React currently only supports piping to one writable stream.',\n        );\n      }\n      hasStartedFlowing = true;\n      prepareForStartFlowingIfBeforeAllReady(request);\n      startFlowing(request, destination);\n      destination.on('drain', createDrainHandler(destination, request));\n      destination.on(\n        'error',\n        createCancelHandler(\n          request,\n          'The destination stream errored while writing data.',\n        ),\n      );\n      destination.on(\n        'close',\n        createCancelHandler(request, 'The destination stream closed early.'),\n      );","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/facebook/react/blob/eafeac097ba51e1eab809c07102126bd5f8e5425/packages/react-dom/src/server/ReactDOMFizzServerNode.js#L126-L162","documentation":"renderToPipeableStream returns a PipeableStream whose pipe(destination) attaches the in-flight Fizz request to a writable stream. A request supports exactly one destination, tracked by a local hasStartedFlowing flag; the second pipe() call on the same object throws error 417. Serving another copy requires a whole new renderToPipeableStream request.","triggerScenarios":"Calling result.pipe(res) twice on the object returned by renderToPipeableStream — once in the main path and again in a retry/timeout/error handler; teeing output by calling pipe on both the HTTP response and a cache stream.","commonSituations":"Express/Fastify handlers that pipe on onShellReady and again in onError recovery; cache middleware that tries to pipe the same render to a second consumer; naive retry logic around shell errors.","solutions":["Guard pipe() with your own boolean and call it exactly once per request; create a new renderToPipeableStream request for any retry","To fan out, pipe once into a Node PassThrough/Transform and tee from that stream","Abort the old request (abort()) before creating a fresh one when re-rendering after an error"],"exampleFix":"// before\nconst {pipe} = renderToPipeableStream(<App />, opts);\npipe(res);\n// retry path later\npipe(res); // throws\n\n// after\nlet piped = false;\nconst stream = renderToPipeableStream(<App />, {\n  ...opts,\n  onShellReady() {\n    if (!piped) { piped = true; stream.pipe(res); }\n  },\n});\n// retries: const retry = renderToPipeableStream(<App />, opts); retry.pipe(res);","handlingStrategy":"validation","validationCode":"let hasPiped = false;\nconst stream = renderToPipeableStream(<App />, {\n  onShellReady() {\n    if (hasPiped) return; // guard against double pipe\n    hasPiped = true;\n    stream.pipe(res);\n  },\n});","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat a PipeableStream as single-use: pipe it exactly once per request","Centralize the pipe call in one place (e.g. onShellReady) instead of piping from multiple handlers","For fan-out, pipe once into a PassThrough and tee downstream","For retries, abort the old request and create a new renderToPipeableStream"],"tags":["react-dom","ssr","streaming","rendertopipeablestream","node"],"backgroundTag":"stream-piped-twice","analyzedSha":"eafeac097ba51e1eab809c07102126bd5f8e5425","analyzedAt":"2026-08-21T22:01:08.818Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}