{"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":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-router/lib/dom/ssr/fog-of-war.ts","lineNumber":342,"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":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/remix-run/react-router/blob/1fd704a7dabcbe3ae09d7387b460e6acaba30ec1/packages/react-router/lib/dom/ssr/fog-of-war.ts#L324-L360","documentation":"In SPA/lazy-route 'fog of war' discovery, the client fetched a manifest patch from the server and received a non-2xx response. The thrown Error carries `${res.status} ${res.statusText}` so callers see the raw HTTP failure, then it propagates up unless the request was aborted.","triggerScenarios":"`fetchAndApplyManifestPatches` calls the manifest patch endpoint (the configured `manifestPath`) and `res.ok` is false. Happens when the dev/asset server returns 4xx/5xx for the patch URL, e.g. behind a reverse proxy that blocks the path, a stale build whose manifest endpoint moved, or an auth/CDN layer returning 403/404.","commonSituations":"Deploying a SPA build behind nginx/CDN that doesn't route the manifest patch path; version skew between client bundle and server manifest; the manifest endpoint returning 500 due to a misconfigured asset server; running a very old client bundle against a newer server.","solutions":["Open the failing patch URL directly in the browser/network tab to see the body and confirm which layer (proxy/CDN/app) returns the error.","Ensure the configured `manifestPath` is served by your host and not blocked by auth or rewrite rules.","Redeploy so client and server share the same build version (clears version-mismatch reload loops).","If behind a CDN, allowlist the manifest path or disable caching on it."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Probe the manifest patch endpoint at startup in production\nasync function pingManifest(url: string) {\n  const res = await fetch(url);\n  if (!res.ok) throw new Error(`manifest endpoint ${res.status}`);\n}\nawait pingManifest(`${origin}/__manifest?paths=/&version=${BUILD_VERSION}`);","typeGuard":null,"tryCatchPattern":"try {\n  await fetchAndApplyManifestPatches(...);\n} catch (e) {\n  if (signal?.aborted) return;\n  // degrade gracefully: route will be discovered on click instead\n  console.warn('manifest patch failed', e);\n}","preventionTips":["Allowlist the manifest path on your CDN/proxy and disable caching for it.","Keep client and server builds version-aligned.","Add a synthetic monitor that hits the manifest endpoint."],"tags":["fog-of-war","manifest","network","spa","lazy-routes"],"backgroundTag":null,"analyzedSha":"1fd704a7dabcbe3ae09d7387b460e6acaba30ec1","analyzedAt":"2026-08-12T13:54:57.804Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}