remix-run/react-router · error
Prerender (resource): Received a
Error message
Prerender (resource): Received a ${response.status} status code from `entry.server.tsx` while prerendering the `${pathname}` path.
${new TextDecoder().decode(contents)} What it means
When prerendering a resource route (a route with no default export, like `routes/robots[.]txt.ts`), React Router requests it from the built server and requires a 200 response. Any other status means the resource route handler failed while generating static output. The error message embeds the decoded response body so you can see the server-side error text.
Solutions
- Run the resource route handler directly (or hit the dev server URL) to reproduce the failure and fix the thrown error
- Make build-time dependencies resilient: guard the external call, cache the result, or commit static content and serve it directly instead of prerendering
- Ensure required environment variables are set in the build/CI environment, not only at runtime
- Drop the resource route from the `prerender` list and generate the file with a script if it cannot succeed at build time
Example fix
// before (app/routes/sitemap[.]xml.ts)
export async function loader() {
let res = await fetch('https://api.example.com/pages');
if (!res.ok) throw new Response('upstream failed', { status: 502 });
return new Response(await res.text());
}
// after — degrade gracefully at build time
export async function loader() {
let res = await fetch('https://api.example.com/pages');
if (!res.ok) {
return new Response('<?xml version="1.0"?><urlset></urlset>', {
headers: { 'Content-Type': 'application/xml' },
});
}
return new Response(await res.text());
} Defensive patterns
Strategy: validation
Validate before calling
// Dry-run a resource route before prerendering it
const res = await fetch(`http://localhost:3000/robots.txt`);
if (!res.ok) {
throw new Error(`Refusing to prerender /robots.txt — dev server returned ${res.status}`);
} Try / catch
try {
await build();
} catch (e) {
if (e instanceof Error && /^Prerender \(resource\)/.test(e.message)) {
// message already embeds the decoded response body — surface it in CI logs
console.error(e.message);
}
} Prevention
- Keep resource-route handlers free of uncached external calls
- Provide build-time fallbacks or committed static files for feeds/sitemaps
- Test resource routes in CI against a locally served build before enabling prerender
When it happens
Trigger: A resource route listed in `prerender` whose handler throws (e.g. external fetch failure during build); a resource route returning `json(..., { status: 500 })`; a resource route relying on runtime-only context (env vars, request cookies) that is absent during the build-time request.
Common situations: Prerendering `robots.txt`, `sitemap.xml`, or RSS feeds whose handlers call slow or rate-limited third-party APIs; resource routes reading `process.env` keys that exist in deploy but not in CI; handlers that redirect (3xx) which are not valid static files.
Related errors
- ⚠️ Paths with dynamic/splat params cannot be prerendered…
- Prerender (data): Received a
- Prerender: Failed to start Vite preview server
- Prerender (html): Received a
- Prerender: Request failed for
AI-assisted analysis of remix-run/react-router@6beaca3952 (2026-08-18).
Data as JSON: /api/errors/141b481dc62e5a41.
Report an issue: GitHub.
Appendix: source
Thrown at packages/react-router-dev/vite/plugin.ts:2585
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.
requests: !metadata.isResourceRoute
? [createRouteRequest(metadata.path, ctx.reactRouterConfig, data)]
: [],
};
}
// Handle resource route responses
if (metadata.type === "resource") {
let pathname = new URL(request.url).pathname;
let contents = new Uint8Array(await response.arrayBuffer());
if (response.status !== 200) {
throw new Error(
`Prerender (resource): Received a ${response.status} status code from ` +
`\`entry.server.tsx\` while prerendering the \`${pathname}\` ` +
`path.\n${new TextDecoder().decode(contents)}`,
);
}
return [
{
path: pathname,
contents,
},
];
}
// Handle document responses (html or spa)
let html = await response.text();
if (metadata.type === "spa") {View on GitHub (pinned to 6beaca3952)