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

  1. Run the failing loader locally and fix it so the prerendered path returns 200 (guard external calls, provide build-time fallback data)
  2. Exclude paths that intentionally error from `prerender` (prune the slug list or use the `prerender` filter function to skip them)
  3. If the path should exist, verify the route pattern matches (params spelled correctly in the file name or route config)
  4. 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

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


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)