remix-run/react-router · error · Error

Unable to fetch new route matches from the server

Error message

Unable to fetch new route matches from the server

What it means

With lazy route discovery (the default in RSC framework mode), navigating to a path the client hasn't seen triggers a manifest fetch (`/__manifest`) to learn new routes. If that fetch fails at the transport level — no body, or a status outside 200–299 — this error is thrown and the navigation errors into the boundary. The 204 + `X-Remix-Reload-Document` case is handled separately as a version-mismatch reload, so plain 4xx/5xx or empty bodies are what land here.

Source

Thrown at packages/react-router/lib/rsc/browser.tsx:1096

  // 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 response = await fetchImplementation(new Request(url, { signal }));
  if (
    clientVersion !== undefined &&
    response.status === 204 &&
    response.headers.has("X-Remix-Reload-Document")
  ) {
    await handleClientVersionMismatch(true, clientVersion, errorReloadPath);
    return;
  }

  if (!response.body || response.status < 200 || response.status >= 300) {
    throw new Error("Unable to fetch new route matches from the server");
  }

  let payload = (await createFromReadableStream(response.body, {
    temporaryReferences: undefined,
  })) as RSCPayload;
  if (payload.type !== "manifest") {
    throw new Error("Failed to patch routes");
  }

  // Track discovered paths so we don't have to fetch them again
  paths.forEach((p) => addToFifoQueue(p, discoveredPaths));

  let patches = await payload.patches;

  // Without the `allowElementMutations` flag, this will no-op if the route
  // already exists so we can just call it for all returned patches
  React.startTransition(() => {
    patches.forEach((p) => {

View on GitHub (pinned to 7aea711dd1)

Solutions

  1. Request the failing `/__manifest?p=...` URL directly and fix whatever answers it: ensure your server/adapter serves the manifest route, or deploy the generated manifest assets.
  2. Exclude `__manifest` from auth redirects so unauthenticated SPA navigations still discover routes (or accept the error boundary).
  3. If it only happens on stale tabs after a deploy, a hard reload resyncs route discovery.
  4. In tests, make sure any fetch mock returns a 200 with a manifest payload for the manifest URL.
Defensive patterns

Strategy: retry

Validate before calling

// deploy smoke test: manifest endpoint must be reachable
const res = await fetch(`${origin}/__manifest?p=${encodeURIComponent("/")}`);
if (!res.ok || !res.body) {
  throw new Error(`route discovery broken: ${res.status}`);
}

Try / catch

export function ErrorBoundary() {
  const error = useRouteError();
  if (error instanceof Error && /Unable to fetch new route matches/.test(error.message)) {
    return <Link reloadDocument to="/">Retry</Link>; // full reload retries discovery
  }
  throw error;
}

Prevention

When it happens

Trigger: The `/__manifest` endpoint returning 404/500 because a custom server or adapter doesn't implement it; auth middleware blocking the manifest request; deploys where manifest files are missing from the static host; offline or network-level failures during navigation to undiscovered routes.

Common situations: Custom servers/edge handlers that route everything to the app and never define `__manifest`; hosting that drops the manifest asset; tests stubbing fetch without covering the manifest URL; firewalls blocking the querystring-heavy manifest URLs.

Related errors


AI-assisted analysis of remix-run/react-router@7aea711dd1 (2026-08-18). Data as JSON: /api/errors/15914658e43778cb. Report an issue: GitHub.