remix-run/react-router · error
${res.status} ${res.statusText}
Error message
${res.status} ${res.statusText} What it means
With fog-of-war route discovery, the client fetches manifest patches for not-yet-discovered routes (a GET to the manifest path with ?paths=...&version=...). If the server answers with a non-2xx status, fetchAndApplyManifestPatches throws the raw `${status} ${statusText}` error (lib/dom/ssr/fog-of-war.ts:342). The status text is the real clue: it tells you why the discovery request failed server-side.
Solutions
- Reproduce the failing request in DevTools (look for the request with ?paths=...&version=... to the manifest path) and check the server response body/logs
- Ensure your host routes ALL requests through the React Router handler (catch-all rewrite/SPA fallback), including query-string URLs
- After deploys, verify version-mismatch handling can fire (204 + X-Remix-Reload-Document) so stale clients hard-reload
- Check that basename and manifest path configuration match the deployment URL space
- If an auth layer guards the manifest path, exempt it or return a valid patch payload
Example fix
// before: static server only serves files, unknown paths 404
// after: fall through to the app handler (express example)
app.use(express.static('build/client'))
app.get('*', createRequestHandler({ build })) Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-deploy check: the manifest patch endpoint must answer 200 with query params
const res = await fetch(`${location.origin}${manifestPath}?paths=/&version=test`);
if (!res.ok) console.error('fog-of-war discovery will fail:', res.status, res.statusText); Try / catch
try {
await discoverRoutes(true);
} catch (e) {
// Non-blocking: log and let navigation-time discovery retry
console.warn('route discovery failed', e);
} Prevention
- Configure a catch-all rewrite so every path (with query strings) reaches the app handler
- Monitor the ?paths=... requests in production (status codes) to catch hosting regressions
- Keep deployments atomic so manifest versions and route handlers deploy together
- Exempt the manifest path from auth redirects or return valid patches from it
When it happens
Trigger: Clicking or preloading (<Link preload>, discoverRoutes(true)) a route not yet in the client manifest while the patch request returns 404/500/401/502; a new deploy invalidated the old client's URLs; a proxy strips query params or redirects the manifest request; static hosting that only serves real files returns 404 for the patched path.
Common situations: Deploying a new build while users hold old tabs (manifest version mismatch without the reload header); SPA/static hosting without a catch-all rewrite to the app; reverse proxies that block or redirect requests with long query strings; auth middleware that intercepts the manifest request and returns 401/302.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- Detected a manifest version mismatch during eager route…
- Detected manifest version mismatch, reloading...
- Unable to fetch new route matches from the server
- Custom Vite manifest paths are not supported
- Failed to patch routes
AI-assisted analysis of remix-run/react-router@7aea711dd1 (2026-08-18).
Data as JSON: /api/errors/f564b7bec8c6f9c6.
Report an issue: GitHub.
Appendix: source
Thrown at packages/react-router/lib/dom/ssr/fog-of-war.ts:335
getManifestPath(manifestPath, basename),
window.location.origin,
);
url.search = searchParams.toString();
// If the URL is nearing the ~8k limit on GET requests, skip this optimization
// step and just let discovery happen on link click. We also wipe out the
// nextPaths Set here so we can start filling it with fresh links
if (url.toString().length > URL_LIMIT) {
nextPaths.clear();
return;
}
let serverPatches: AssetsManifest["routes"];
try {
let res = await fetch(url, { signal });
if (!res.ok) {
throw new Error(`${res.status} ${res.statusText}`);
}
if (
await handleClientVersionMismatch(
res.status === 204 && res.headers.has("X-Remix-Reload-Document"),
manifest.version,
errorReloadPath,
)
) {
return;
}
serverPatches = (await res.json()) as AssetsManifest["routes"];
} catch (e) {
if (signal?.aborted) return;
throw e;
}
View on GitHub (pinned to 7aea711dd1)