remix-run/react-router · error · Error

Error splitting route module: ${id} ${invalidChunks.map((na

Error message

Error splitting route module: ${id}

${invalidChunks.map((name) => `- ${name}`).join("\n")}

${plural ? "These exports" : "This export"} could not be split into ${plural ? "their own chunks" : "its own chunk"} because ${plural ? "they share" : "it shares"} code with other exports. You should extract any shared code into its own module and then import it within the route module.

What it means

Thrown by validateRouteChunks in virtual-route-modules.ts when the RSC chunk-splitting pass cannot isolate one or more client-side exports (clientAction, clientLoader, clientMiddleware, HydrateFallback) into their own chunk because they share code with other exports. The error names the offending export(s) and the module id, then advises extracting shared code into a separate module. Only non-root routes are chunked.

Source

Thrown at packages/react-router-dev/vite/rsc/virtual-route-modules.ts:550

function validateRouteChunks({
  id,
  valid,
}: {
  id: string;
  valid: Record<Exclude<RouteChunkName, "main">, boolean>;
}): void {
  let invalidChunks = Object.entries(valid)
    .filter(([_, isValid]) => !isValid)
    .map(([chunkName]) => chunkName);

  if (invalidChunks.length === 0) {
    return;
  }

  let plural = invalidChunks.length > 1;

  throw new Error(
    [
      `Error splitting route module: ${id}`,

      invalidChunks.map((name) => `- ${name}`).join("\n"),

      `${plural ? "These exports" : "This export"} could not be split into ${
        plural ? "their own chunks" : "its own chunk"
      } because ${
        plural ? "they share" : "it shares"
      } code with other exports. You should extract any shared code into its own module and then import it within the route module.`,
    ].join("\n\n"),
  );
}

View on GitHub (pinned to 1fd704a7da)

Solutions

  1. Extract the shared code into its own module (separate file) and import it from both the server and client exports — the analyzer can then keep the shared module as a dependency rather than duplicating it.
  2. If the shared value is only used by the client export, move it next to the client export so the server export no longer references it.
  3. For types-only sharing, use `import type` so they are erased and don't couple chunks.
  4. After refactoring, rebuild to let _detectRouteChunks re-evaluate chunk boundaries.

Example fix

// app/routes/foo.tsx — before (shared helper couples loader + clientAction)
import { validate } from '~/utils/validate'; // runtime import shared across boundary
export async function loader() { validate(/* … */); /* … */ }
export async function clientAction() { validate(/* … */); /* … */ }
// after — keep imports type-only where possible, or move runtime helper next to client export
// app/routes/foo.tsx
import type { ValidateFn } from '~/utils/validate';
import { validate } from './foo.client'; // client-local module
export async function loader() { /* server-only validation */ }
export async function clientAction() { validate(/* … */); }
Defensive patterns

Strategy: validation

Validate before calling

// crude heuristic: flag non-root route modules where a runtime import is shared
// between a server export (loader/action/middleware) and a client export (clientAction/clientLoader/clientMiddleware/HydrateFallback)
import { parse } from '@babel/parser';
// (implement a small AST check) — if a top-level runtime import is referenced in both groups, refactor

Try / catch

try { await viteBuild(); }
catch (e) {
  if (e instanceof Error && e.message.startsWith('Error splitting route module:')) {
    // parse the listed export(s); extract shared code into a separate module and rebuild
  }
  throw e;
}

Prevention

When it happens

Trigger: A non-root route module imports a shared helper or constant at module top-level and uses it from BOTH a server export (e.g. loader) and a client export (e.g. clientAction/HydrateFallback). The chunk analyzer marks that client export's chunk as invalid (shared code can't be split cleanly), and validateRouteChunks throws.

Common situations: A shared utility, constant, or type (especially runtime values) imported across the boundary between a loader and a clientAction/HydrateFallback. Co-locating shared validation logic used by both loader and clientAction. Bundler inlining a small shared value so both chunks retain it.

Related errors


AI-assisted analysis of remix-run/react-router@1fd704a7da (2026-08-12). Data as JSON: /api/errors/822f3cb6e12a78dd. Report an issue: GitHub.