reflex-dev/reflex · warning

react-router hmr runtime changed; unloaded-route HMR patch s

Error message

react-router hmr runtime changed; unloaded-route HMR patch skipped

What it means

This is a JavaScript console warning emitted by a Vite plugin that Reflex injects into its generated vite.config.js. The plugin patches react-router's HMR runtime module (virtual:react-router/hmr-runtime) to replace the 'unloaded-route' throw with a no-op so HMR works with lazily loaded routes. When react-router changes its internal code shape, the regex (unloadedRouteThrow) no longer matches and the patch is skipped with this warning.

Source

Thrown at packages/reflex-base/src/reflex_base/compiler/templates.py:706

      }});
      return [];
    }}
  }};
}}

// React Router queues manifest updates for lazy routes even when their modules
// are not loaded. Its HMR runtime throws on those entries before clearing the
// queue, which blocks every later update until the browser is reloaded.
function patchReactRouterHmrRuntime() {{
  const unloadedRouteThrow = /if\s*\(!imported\)\s*\{{\s*throw\s+Error\(\s*`\[react-router:hmr\] No module update found for route [^`]+`,\s*\);\s*\}}/;
  return {{
    name: "reflex-patch-react-router-hmr-runtime",
    apply: "serve",
    enforce: "post",
    transform(code, id) {{
      if (id !== "\0virtual:react-router/hmr-runtime") return;
      if (!unloadedRouteThrow.test(code)) {{
        this.warn(
          "react-router hmr runtime changed; unloaded-route HMR patch skipped",
        );
        return;
      }}
      return {{
        code: code.replace(unloadedRouteThrow, "if (!imported) continue;"),
        map: null,
      }};
    }},
  }};
}}

export default defineConfig((config) => ({{
  base: "{base}",
  plugins: [
    alwaysUseReactDomServerNode(),
    reactRouter(),
    patchReactRouterHmrRuntime(),

View on GitHub (pinned to 45b8ed5ab7)

Solutions

  1. Check your installed react-router/@react-router/dev version and align it with the version Reflex generates/pins in the output frontend package.json (remove manual overrides and re-run `reflex export --frontend` or delete .web and let it regenerate).
  2. Upgrade Reflex/reflex-base to the latest release, which may update the unloadedRouteThrow pattern for newer react-router.
  3. If HMR breaks (browser 'You cannot HMR an unloaded route' errors), restart `reflex dev` — full reload still works since only the HMR patch is skipped.
  4. Report the react-router version to the Reflex repo so the pattern in compiler/templates.py vite_config_template can be updated.

Example fix

// before (user package.json override in .web)
"overrides": { "react-router": "^7.2.0" }

// after: remove the override and use the version reflex generates
// delete .web / node_modules and re-run `reflex dev`
Defensive patterns

Strategy: validation

Validate before calling

// in generated .web, before `npm run dev` type checks are not possible; instead check the installed version
// package.json of the exported frontend
"require('react-router/package.json').version" // verify it matches the version reflex pins; if not, reinstall deps

Prevention

When it happens

Trigger: Running `reflex dev` (Vite serve mode) after upgrading react-router (or @react-router/dev) to a version whose hmr-runtime module no longer contains the expected unloaded-route throw statement. The warning comes from the plugin's transform() hook when id === '\0virtual:react-router/hmr-runtime' but the pattern test fails.

Common situations: A reflex-base or Reflex framework bump pulls in a newer react-router version; or a user pins/overrides react-router in their project's package.json to an incompatible version. HMR of routes may then throw 'Unloaded route' errors in the browser on hot updates.


AI-assisted analysis of reflex-dev/reflex@45b8ed5ab7 (2026-08-28). Data as JSON: /api/errors/c79391919b557bf5. Report an issue: GitHub.