remix-run/react-router · error · Error
Prerender (data): Received a
Error message
Prerender (data): Received a ${response.status} status code from `entry.server.tsx` while prerendering the `${metadata.path}` path.
${pathname} What it means
During prerendering with a data strategy, React Router issues a data request against the built server and inspects the response in `postProcess`. Only 200 (success) and 202 (accepted/streamed) are allowed for `.data` requests; anything else means a loader or the server render pipeline produced an error status for a path you asked to prerender. The thrown error includes the pathname and attaches the original response as `cause` so you can inspect the body.
Solutions
- Run the failing loader locally and fix it so the prerendered path returns 200 (guard external calls, provide build-time fallback data)
- Exclude paths that intentionally error from `prerender` (prune the slug list or use the `prerender` filter function to skip them)
- If the path should exist, verify the route pattern matches (params spelled correctly in the file name or route config)
- Inspect `error.cause` (the Response) to read the exact error body returned by the server
Example fix
// before (app/routes/blog.$slug.tsx)
export async function loader({ params }: Route.LoaderArgs) {
let post = await getPost(params.slug);
if (!post) throw data('Not Found', { status: 404 });
return { post };
}
// after — skip erroring paths at prerender time
// (react-router.config.ts)
export default {
async prerender({ getStaticPaths }) {
return (await getStaticPaths()).filter(
(p) => !p.startsWith('/blog/drafts/')
);
},
}; Defensive patterns
Strategy: validation
Validate before calling
// react-router.config.ts — verify each prerender path succeeds before build
export default {
async prerender({ getStaticPaths }) {
const ok: string[] = [];
for (const p of await getStaticPaths()) {
const res = await fetch(`http://localhost:3000${p}.data`, { // local dev server
headers: { 'X-React-Router-Prerender': '1' },
});
if (res.ok) ok.push(p);
}
return ok;
},
}; Try / catch
try {
await build();
} catch (e) {
if (e instanceof Error && /^Prerender \(data\)/.test(e.message)) {
// e.cause is the failed Response — read its body for the loader error
const body = await (e.cause as Response).text();
console.error('Loader failed during prerender:', body);
}
} Prevention
- Make loaders deterministic and guarded against build-time API failures
- Prune intentional 404/500 slugs from `prerender` via its filter function
- Set required env vars in CI before `react-router build`
When it happens
Trigger: A `prerender` entry whose loader throws or calls `data()`/`json()` with 4xx/5xx (e.g. a loader that 404s for missing content); an entry.server.tsx that returns a non-200 render for that path; a document redirect leaking into the data request; loaders that depend on request headers absent during prerender.
Common situations: Prerendering dynamic paths (`prerender: ['/blog/*']`) where some slugs legitimately 404 from the loader; loaders reading `request.headers` (host, cookie) that fall back to error responses during static generation; a root loader hitting an external API that fails during build.
Related errors
- ⚠️ Paths with dynamic/splat params cannot be prerendered…
- Prerender: Failed to start Vite preview server
- Prerender (html): Received a
- Prerender: Request failed for
- Prerender: Request failed for
AI-assisted analysis of remix-run/react-router@6beaca3952 (2026-08-18).
Data as JSON: /api/errors/d6c310af3564b745.
Report an issue: GitHub.
Appendix: source
Thrown at packages/react-router-dev/vite/plugin.ts:2554
// When `ssr:false` is set, we always want a SPA HTML they can use
// to serve non-prerendered routes. This file will only SSR the root
// route and can hydrate for any path.
if (!ctx.reactRouterConfig.ssr) {
requests.push(createSpaModeRequest(ctx.reactRouterConfig));
}
return requests;
},
async postProcess(request, response, metadata) {
invariant(metadata);
// Handle loader data responses
if (metadata.type === "data") {
let pathname = new URL(request.url).pathname;
if (response.status !== 200 && response.status !== 202) {
throw new Error(
`Prerender (data): Received a ${response.status} status code from ` +
`\`entry.server.tsx\` while prerendering the \`${metadata.path}\` ` +
`path.\n${pathname}`,
{ cause: response },
);
}
let data = await response.text();
return {
files: [
{
path: pathname,
contents: data,
},
],
// After saving the .data file, request the HTML page.
// The data is passed along to be embedded in the response header.View on GitHub (pinned to 6beaca3952)