{"record":{"id":"705d2de445648b52","repo":"remix-run/react-router","slug":"unable-to-decode-turbo-stream-response","errorCode":null,"errorMessage":"Unable to decode turbo-stream response","messagePattern":"Unable to decode turbo-stream response","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-router/lib/dom/ssr/single-fetch.tsx","lineNumber":664,"sourceCode":"    } else {\n      let typed = decoded.value as SingleFetchResult;\n      let routeId = targetRoutes?.[0];\n      invariant(routeId, \"No routeId found for single fetch call decoding\");\n      if (\"redirect\" in typed) {\n        data = { redirect: typed };\n      } else {\n        data = { routes: { [routeId]: typed } };\n      }\n    }\n    return { status: res.status, data };\n  } catch {\n    // Can't clone after consuming the body via turbo-stream so we can't\n    // include the body here.  In an ideal world we'd look for a turbo-stream\n    // content type here, or even X-Remix-Response but then folks can't\n    // statically deploy their prerendered .data files to a CDN unless they can\n    // tell that CDN to add special headers to those certain files - which is a\n    // bit restrictive.\n    throw new Error(\"Unable to decode turbo-stream response\");\n  }\n}\n\n// Note: If you change this function please change the corresponding\n// encodeViaTurboStream function in server-runtime\nexport function decodeViaTurboStream(\n  body: ReadableStream<Uint8Array>,\n  global: Window | typeof globalThis,\n) {\n  return decode(body, {\n    plugins: [\n      (type: string, ...rest: unknown[]) => {\n        // Decode Errors back into Error instances using the right type and with\n        // the right (potentially undefined) stacktrace\n        if (type === \"SanitizedError\") {\n          let [name, message, stack] = rest as [\n            string,\n            string,","sourceCodeStart":646,"sourceCodeEnd":682,"githubUrl":"https://github.com/remix-run/react-router/blob/6beaca39526d5716c3c112ebb0782765baa5a9ce/packages/react-router/lib/dom/ssr/single-fetch.tsx#L646-L682","documentation":"With the single-fetch data strategy, loader/action results come back from a `.data` request encoded as a turbo-stream. The client runs `decodeViaTurboStream` on the response body inside a try/catch; any decoding failure (body not turbo-stream bytes, corrupted stream) hits the catch, which deliberately throws this generic error because the body has already been consumed and cannot be re-read or echoed. This means the response you received was not a valid turbo-stream payload.","triggerScenarios":"A proxy, auth gateway, or service worker intercepting the `.data` request and returning an HTML login/404 page instead of the turbo-stream body; a CDN serving a stale or wrong-content-type prerendered `.data` file; double compression (gzip/brotli applied twice) mangling the stream; severe client/server version skew after a deploy where old client code decodes a new server encoding.","commonSituations":"Corporate proxies or API gateways rewriting responses for non-HTML content types; hosting static prerendered `.data` files with wrong MIME/compression settings; a middleware returning `json()` for `.data` requests; deploys where the browser holds an old HTML bundle that requests `.data` from a new server.","solutions":["Open the network tab and inspect the failing `.data` request — the response body is almost certainly an HTML error/login page or empty; fix whatever serves it (auth redirect, 404 handler, gateway rule) to let the router's own response through.","Exclude `.data` requests (by path suffix or `X-Remix-`/React Router data headers) from interceptors, service workers, and compression layers.","If it happens right after a deploy, hard-refresh or clear the cache so client and server encodings match.","For prerendered static hosting, verify the deployed `.data` files are byte-identical to the build output and served uncompressed-as-built."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// in a route error boundary\nexport function ErrorBoundary() {\n  const error = useRouteError();\n  if (error instanceof Error && /turbo-stream/.test(error.message)) {\n    return <button onClick={() => window.location.reload()}>Session out of date — reload</button>;\n  }\n  throw error;\n}","preventionTips":["Bypass proxies/service workers for .data requests (match on the .data suffix).","Serve prerendered .data files with the exact bytes and content type produced by the build.","After deploys, prompt users to reload so client and server encodings match."],"tags":["single-fetch","turbo-stream","network","decoding"],"backgroundTag":"response-decoding-failed","analyzedSha":"6beaca39526d5716c3c112ebb0782765baa5a9ce","analyzedAt":"2026-08-18T18:04:14.938Z","contentChangedAt":"2026-08-18T18:04:14.938Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}