remix-run/react-router · error · Error

Prerender: No resolved URL is available from the Vite previe

Error message

Prerender: No resolved URL is available from the Vite preview server

What it means

Thrown by getResolvedUrl() when a Vite PreviewServer that started successfully nonetheless exposes no local resolved URL (previewServer.resolvedUrls?.local[0] is falsy). React Router needs that base URL to issue prerender requests, so it cannot proceed. It indicates the preview server came up in an unusual state rather than failing outright.

Source

Thrown at packages/react-router-dev/vite/plugins/prerender.ts:571

      configFile: viteConfig.configFile,
      logLevel: "silent",
      preview: {
        port: 0,
        open: false,
      },
    });
  } catch (error) {
    throw new Error("Prerender: Failed to start Vite preview server", {
      cause: error,
    });
  }
}

function getResolvedUrl(previewServer: Vite.PreviewServer): URL {
  const baseUrl = previewServer.resolvedUrls?.local[0];

  if (!baseUrl) {
    throw new Error(
      "Prerender: No resolved URL is available from the Vite preview server",
    );
  }

  return new URL(baseUrl);
}

View on GitHub (pinned to 1fd704a7da)

Solutions

  1. Check Vite version compatibility with your @react-router/dev version (peerDependencies) and align majors.
  2. Remove or audit any custom `preview.host` / `server.host` overrides in vite.config that could suppress the local URL.
  3. Reproduce with a bare `vite preview` and log `server.resolvedUrls` to confirm Vite itself populates local[0].
  4. Disable third-party Vite plugins one by one to find one that mutates resolvedUrls.
  5. Update @react-router/dev to a patch release that may read resolvedUrls more defensively.

Example fix

// vite.config.ts — avoid forcing a host that drops the local URL
// before
export default defineConfig({ server: { host: '0.0.0.0' }, preview: { host: '0.0.0.0' } });
// after (let Vite bind local + network)
export default defineConfig({ server: { host: true }, preview: { host: true } });
Defensive patterns

Strategy: validation

Validate before calling

import { createServer } from 'vite';
const preview = await (await import('vite')).preview({ /* same opts */ });
const hasLocalUrl = !!preview.resolvedUrls?.local?.[0];
if (!hasLocalUrl) console.warn('Vite preview produced no local URL — check server.host/preview.host config.');

Type guard

function hasResolvedLocalUrl(s: { resolvedUrls?: { local?: Array<string | undefined> } }): boolean {
  return !!s.resolvedUrls?.local?.[0];
}

Try / catch

try { await runPrerender(); }
catch (e) {
  if (e instanceof Error && /No resolved URL is available/.test(e.message)) {
    // inspect vite.config preview.host/server.host and retry without forced host
  }
  throw e;
}

Prevention

When it happens

Trigger: vite.preview() resolved to a PreviewServer object whose resolvedUrls is undefined or whose local array is empty. This happens when Vite's preview server did not bind a local interface (e.g. host config forces a non-local binding that Vite classifies only as network, or a custom Vite version/plugin mutates resolvedUrls).

Common situations: A Vite version regression where resolvedUrls is populated asynchronously and read too early. Custom server.host config (e.g. host:'0.0.0.0' only) that omits a local entry. A preview plugin that overrides resolvedUrls. Mismatched @vitejs/* plugin versions against the installed Vite major.

Related errors


AI-assisted analysis of remix-run/react-router@1fd704a7da (2026-08-12). Data as JSON: /api/errors/1c01e8505bed1a17. Report an issue: GitHub.