{"record":{"id":"f564b7bec8c6f9c6","repo":"remix-run/react-router","slug":"res-status-res-statustext","errorCode":null,"errorMessage":"${res.status} ${res.statusText}","messagePattern":"\\$\\{res\\.status\\} \\$\\{res\\.statusText\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/react-router/lib/dom/ssr/fog-of-war.ts","lineNumber":335,"sourceCode":"    getManifestPath(manifestPath, basename),\n    window.location.origin,\n  );\n  url.search = searchParams.toString();\n\n  // If the URL is nearing the ~8k limit on GET requests, skip this optimization\n  // step and just let discovery happen on link click.  We also wipe out the\n  // nextPaths Set here so we can start filling it with fresh links\n  if (url.toString().length > URL_LIMIT) {\n    nextPaths.clear();\n    return;\n  }\n\n  let serverPatches: AssetsManifest[\"routes\"];\n  try {\n    let res = await fetch(url, { signal });\n\n    if (!res.ok) {\n      throw new Error(`${res.status} ${res.statusText}`);\n    }\n\n    if (\n      await handleClientVersionMismatch(\n        res.status === 204 && res.headers.has(\"X-Remix-Reload-Document\"),\n        manifest.version,\n        errorReloadPath,\n      )\n    ) {\n      return;\n    }\n\n    serverPatches = (await res.json()) as AssetsManifest[\"routes\"];\n  } catch (e) {\n    if (signal?.aborted) return;\n    throw e;\n  }\n","sourceCodeStart":317,"sourceCodeEnd":353,"githubUrl":"https://github.com/remix-run/react-router/blob/7aea711dd1ae2bc5a076d13ff17291829690fa74/packages/react-router/lib/dom/ssr/fog-of-war.ts#L317-L353","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: static server only serves files, unknown paths 404\n// after: fall through to the app handler (express example)\napp.use(express.static('build/client'))\napp.get('*', createRequestHandler({ build }))","handlingStrategy":"try-catch","validationCode":"// Pre-deploy check: the manifest patch endpoint must answer 200 with query params\nconst res = await fetch(`${location.origin}${manifestPath}?paths=/&version=test`);\nif (!res.ok) console.error('fog-of-war discovery will fail:', res.status, res.statusText);","typeGuard":null,"tryCatchPattern":"try {\n  await discoverRoutes(true);\n} catch (e) {\n  // Non-blocking: log and let navigation-time discovery retry\n  console.warn('route discovery failed', e);\n}","preventionTips":["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"],"tags":["fog-of-war","lazy-routes","manifest","network","deployment"],"backgroundTag":"http-request-failed","analyzedSha":"7aea711dd1ae2bc5a076d13ff17291829690fa74","analyzedAt":"2026-08-18T18:04:14.938Z","contentChangedAt":"2026-08-18T18:04:14.938Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}