remix-run/react-router · error
Prerender: Request failed for
Error message
Prerender: Request failed for ${prerenderPath}: ${response.status} ${response.statusText} What it means
The prerender plugin ships a `defaultPostProcess` used when no custom postprocess is configured: it requests each path from a Vite preview server of your built app and rejects any non-OK response. This is the last line of defense so error pages are never written out as static HTML; unlike the framework-mode postProcess variants, it does not embed the body, only status and statusText.
Solutions
- Reproduce with `react-router-serve ./build/server/index.js` (or vite preview) and curl the exact path to see the real error
- Fix the loader/middleware so the path returns 200, or drop the path from the prerender list
- Provide a custom `postprocess` hook if you need different status handling (e.g. allow specific non-200s)
Example fix
// before — default postprocess rejects any non-200
prerender({ postProcess: undefined });
// after — custom postprocess that tolerates 404s
prerender({
postProcess: async (request, response) => {
if (response.status === 404) return []; // skip, don't emit
return defaultPostProcess(request, response);
},
}); Defensive patterns
Strategy: fallback
Validate before calling
// Pre-validate all paths against a preview of the build
const results = await Promise.all(
paths.map(async (p) => [p, (await fetch(`${base}${p}`)).ok] as const),
);
const goodPaths = results.filter(([, ok]) => ok).map(([p]) => p); Try / catch
try {
await prerender({ paths: goodPaths });
} catch (e) {
if (e instanceof Error && /^Prerender: Request failed/.test(e.message)) {
// retry once, then report the failing path + status from the message
}
} Prevention
- Smoke-test every path via `vite preview` + curl before prerendering
- Supply a custom `postProcess` when some non-200s are acceptable
- Watch path casing — CI on Linux is case-sensitive
When it happens
Trigger: Using the prerender plugin with its default postprocess where any requested path returns 4xx/5xx from the preview server (loader throw, middleware rejection, entry.server error); a request that gets redirected into a 404; wrong casing in the requested path on a case-sensitive server.
Common situations: Library/tool authors embedding `@react-router/dev`'s prerender plugin; prerendering pages whose loaders fail in CI; case-sensitivity differences between macOS dev and Linux CI.
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/42bddb2cf447683e.
Report an issue: GitHub.
Appendix: source
Thrown at packages/react-router-dev/vite/plugins/prerender.ts:424
},
},
};
},
},
configResolved(resolvedConfig) {
viteConfig = resolvedConfig;
},
};
}
async function defaultPostProcess(
request: Request,
response: Response,
): Promise<PrerenderFile[]> {
const prerenderPath = new URL(request.url).pathname;
if (!response.ok) {
throw new Error(
`Prerender: Request failed for ${prerenderPath}: ${response.status} ${response.statusText}`,
);
}
return [
{
path: `${prerenderPath}/index.html`,
contents: await response.text(),
},
];
}
function defaultHandleError(request: Request, error: Error): void {
const prerenderPath = new URL(request.url).pathname;
if (request.signal?.aborted) {
throw new Error(
`Prerender: Request timed out for ${prerenderPath}: ${error.message}`,View on GitHub (pinned to 6beaca3952)