{"record":{"id":"cccf0aab1b2b104a","repo":"remix-run/react-router","slug":"spa-mode-received-a-response-status-status-cod","errorCode":null,"errorMessage":"SPA Mode: Received a ${response.status} status code from `entry.server.tsx` while prerendering your SPA Fallback HTML file.\n${html}","messagePattern":"SPA Mode: Received a (.+?) status code from `entry\\.server\\.tsx` while prerendering your SPA Fallback HTML file\\.\n(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/react-router-dev/vite/plugin.ts","lineNumber":2605,"sourceCode":"                `\\`entry.server.tsx\\` while prerendering the \\`${pathname}\\` ` +\n                `path.\\n${new TextDecoder().decode(contents)}`,\n            );\n          }\n\n          return [\n            {\n              path: pathname,\n              contents,\n            },\n          ];\n        }\n\n        // Handle document responses (html or spa)\n        let html = await response.text();\n\n        if (metadata.type === \"spa\") {\n          if (response.status !== 200) {\n            throw new Error(\n              `SPA Mode: Received a ${response.status} status code from ` +\n                `\\`entry.server.tsx\\` while prerendering your SPA Fallback HTML file.\\n` +\n                html,\n            );\n          }\n\n          if (\n            !html.includes(\"window.__reactRouterContext =\") ||\n            !html.includes(\"window.__reactRouterRouteModules =\")\n          ) {\n            throw new Error(\n              \"SPA Mode: Did you forget to include `<Scripts/>` in your root route? \" +\n                \"Your pre-rendered HTML cannot hydrate without `<Scripts />`.\",\n            );\n          }\n\n          // SPA fallback is written to root regardless of basename\n          return [","sourceCodeStart":2587,"sourceCodeEnd":2623,"githubUrl":"https://github.com/remix-run/react-router/blob/6beaca39526d5716c3c112ebb0782765baa5a9ce/packages/react-router-dev/vite/plugin.ts#L2587-L2623","documentation":"With `ssr: false` (SPA Mode), React Router prerenders a fallback HTML shell by rendering `/` through your `entry.server.tsx`. That render must return 200; any other status means the SPA shell itself failed to render, and since the fallback is the only HTML a SPA has, the build aborts. The offending HTML is included in the message.","triggerScenarios":"`ssr: false` in react-router.config.ts combined with an entry.server render path that returns an error status (throwing in the root route's default export, a failing root loader without prerender, an ErrorBoundary rendering during the fallback request); a custom entry.server.tsx that inspects the request and responds non-200 for `/`.","commonSituations":"Enabling SPA Mode on an app whose root loader throws at build time; entry.server.tsx copied from an SSR setup that returns `new Response(..., { status: 500 })` on render errors without handling the SPA fallback; root ErrorBoundary triggering because a context provider reads server-only data.","solutions":["Check the HTML in the error message — it is usually the rendered error boundary showing the real exception","Fix the throw in the root route / entry.server.tsx so `/` renders 200 in a build environment","If a root loader exists in SPA Mode, either prerender `/` or move the logic to `clientLoader`","Simplify by removing a custom entry.server.tsx so the framework default shell is used"],"exampleFix":"// before (app/root.tsx) — throws during SPA fallback render\nexport async function loader() {\n  throw new Error('DB unavailable at build time');\n}\n\n// after — no server loader in SPA Mode; load on the client\nexport async function clientLoader() {\n  return { user: await fetch('/api/me').then((r) => r.json()) };\n}","handlingStrategy":"validation","validationCode":"// Verify the SPA fallback renders 200 before building\n// (run `react-router-serve` or `vite dev` and request '/')\nconst res = await fetch('http://localhost:3000/');\nif (res.status !== 200) throw new Error(`Root render returned ${res.status} — fix before SPA build`);","typeGuard":null,"tryCatchPattern":"try {\n  await build();\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('SPA Mode: Received a')) {\n    // the message embeds the rendered error HTML — inspect it for the throw site\n  }\n}","preventionTips":["In SPA Mode, avoid root `loader`s or ensure `/` is prerendered successfully","Test that `/` renders without errors in dev before building with `ssr: false`","Don't return non-200 responses from entry.server.tsx for the root path"],"tags":["spa-mode","ssr-false","prerender","entry-server"],"backgroundTag":"prerender-response-error","analyzedSha":"6beaca39526d5716c3c112ebb0782765baa5a9ce","analyzedAt":"2026-08-18T18:04:14.938Z","contentChangedAt":"2026-08-18T18:04:14.938Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}