{"record":{"id":"f17aedd98e97bea3","repo":"remix-run/react-router","slug":"spa-mode-did-you-forget-to-include-scripts-i","errorCode":null,"errorMessage":"SPA Mode: Did you forget to include `<Scripts/>` in your root route? Your pre-rendered HTML cannot hydrate without `<Scripts />`.","messagePattern":"SPA Mode: Did you forget to include `<Scripts/>` in your root route\\? Your pre-rendered HTML cannot hydrate without `<Scripts />`\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/react-router-dev/vite/plugin.ts","lineNumber":2616,"sourceCode":"        }\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 [\n            {\n              path: \"/__spa-fallback.html\",\n              contents: html,\n            },\n          ];\n        }\n\n        // Handle html responses\n        let pathname = new URL(request.url).pathname;\n\n        if (redirectStatusCodes.has(response.status)) {","sourceCodeStart":2598,"sourceCodeEnd":2634,"githubUrl":"https://github.com/remix-run/react-router/blob/6beaca39526d5716c3c112ebb0782765baa5a9ce/packages/react-router-dev/vite/plugin.ts#L2598-L2634","documentation":"In SPA Mode the prerendered fallback HTML must contain the `window.__reactRouterContext` and `window.__reactRouterRouteModules` assignments, which `<Scripts />` from `react-router` emits. If either marker is missing, hydration in the browser would silently fail, so the build fails fast with a pointer to the missing component. Custom root layouts or error documents that omit `<Scripts />` are the usual cause.","triggerScenarios":"`ssr: false` with a root route whose HTML shell does not render `<Scripts />` (e.g. hand-written `<html>` without it); `<Scripts />` commented out to avoid a flash; a custom entry.server.tsx that strips scripts from the output; conditional rendering that excludes `<Scripts />` on the server pass.","commonSituations":"Converting an existing React SPA to React Router SPA Mode and hand-rolling the document; removing `<Scripts />` while debugging; early-returns in the Root component for loading states that skip the document structure.","solutions":["Import `Scripts` from `react-router` and render it inside `<body>` in the root route's default export (and any custom ErrorBoundary that renders a full document)","Verify the root returns a complete `<html><head/><body>…<Scripts/></body></html>` structure","Remove custom entry.server.tsx transformations that drop script tags"],"exampleFix":"// before (app/root.tsx)\nimport { Outlet } from 'react-router';\nexport default function Root() {\n  return (\n    <html>\n      <head />\n      <body>\n        <Outlet />\n      </body>\n    </html>\n  );\n}\n\n// after\nimport { Outlet, Scripts } from 'react-router';\nexport default function Root() {\n  return (\n    <html>\n      <head />\n      <body>\n        <Outlet />\n        <Scripts />\n      </body>\n    </html>\n  );\n}","handlingStrategy":"validation","validationCode":"// Assert the root document includes Scripts before SPA build\nimport Root from './app/root';\n// simplest guard: grep the source\nconst src = fs.readFileSync('app/root.tsx', 'utf8');\nif (!/\\<Scripts\\s*\\/?\\>/.test(src)) {\n  throw new Error('Root route must render <Scripts /> for SPA Mode');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await build();\n} catch (e) {\n  if (e instanceof Error && e.message.includes('<Scripts/>')) {\n    console.error('Add <Scripts /> from react-router to app/root.tsx');\n    process.exit(1);\n  }\n  throw e;\n}","preventionTips":["Always render `<Scripts />` (and `<ScrollRestoration />` if used) inside `<body>` of the root route","Include `<Scripts />` in any custom root ErrorBoundary that renders a full document","Start SPA projects from the official SPA template"],"tags":["spa-mode","ssr-false","hydration","scripts-component"],"backgroundTag":"missing-scripts-component","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"}