Skip to content

Route module load failure during client navigation reloads the current page instead of the navigation target #15567

Open

Description

@hackonhari

Reproduction

Framework mode, production build (react-router build), route /todos code-split into assets/todos-*.js.

  1. Load /, which has <Link to="/todos">.
  2. Make the first request for the /todos route chunk fail (dropped connection). Playwright:
    let blocked = 0;
    await page.route(/\/assets\/todos-[^/]+\.js$/, (route) =>
      blocked++ === 0 ? route.abort("connectionreset") : route.continue(),
    );
    await page.goto("http://localhost:8787/", { waitUntil: "networkidle" });
    await page.locator('a[href="/todos"]').click();
  3. loadRouteModule logs Error loading route module `/assets/todos-*.js`, reloading page... and calls window.location.reload().

Result: exactly one document reload, and the page ends on /, not /todos. The retried chunk request would have succeeded, but the reload is for the location the user was leaving, so the user sees a flash and stays where they were. They have to click again.

With a permanently failing chunk the same code path reloads once and stops, so there is no loop; only the destination is lost.

System Info

System:
  OS: Linux 5.15 Ubuntu 22.04.5 LTS
Binaries:
  Node: 22.23.0
Browsers:
  Chrome: 142.0.7444.134
npmPackages:
  @react-router/dev: 8.4.0
  react-router: 8.4.0
  vite: 8.3.1

Used Package Manager

npm

Expected Behavior

When a route module fails to load during a client-side navigation, the recovery reload lands on the navigation's target location (for example, a hard navigation to the target URL instead of window.location.reload()), so a transient network failure costs one full page load rather than the navigation.

Actual Behavior

loadRouteModule (lib/dom/ssr/routeModules.ts) calls window.location.reload(). The navigation to /todos has not been committed yet, so the reload re-requests / and the navigation is dropped.

Context: a production app of ours sees this class of chunk-fetch failure regularly from mobile connections, proxies and content blockers (the asset still returns 200 on retry), so each occurrence currently costs the user a lost click.

Activity

  1. sakura168899-debug commented on Oct 3, 2026

    @sakura168899-debug

    I traced current main at a6090382ed467b5a2d46c8de1a13b331f14959f8 before attempting a patch. The hard reload is in packages/react-router/lib/dom/ssr/routeModules.ts#loadRouteModule, but that function only receives the EntryRoute and module cache. createClientRoutes closes it into the route lazy callbacks; LazyRouteFunction is zero-argument, and router.ts#loadLazyRoute calls it without the pending Location.

    That means replacing window.location.reload() with route.path would not be safe: the route pattern can lose dynamic parameters, search parameters, and hash. The full destination exists earlier in router.ts#startNavigation(historyAction, location, ...), but it is not propagated to framework route-module loading.

    Is there an intended recovery hook or preferred way to carry the pending navigation location to this loader? With that direction, I can prepare a focused regression test and PR rather than guessing at a new context path.

  2. NikitaIT commented on Oct 12, 2026

    @NikitaIT

    Error loading module ...*.js is a common issue with Cloudflare Pages (static hosting) after all redeployments.
    I've mentioned this same location reload issue multiple times when navigating via Link after redeployment. So, I can confirm it's a big problem for pre-rendered pages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions