Skip to content

Concurrent Vite config resolution can leak route state between Framework Mode apps using flatRoutes() #15007

@razakiau

Description

@razakiau

Reproduction

Failing test branch: https://github.com/razakiau/react-router/blob/bug-report/concurrent-vite-config-route-state/integration/bug-report-test.ts

I first hit this in an Nx workspace on React Router 7.8.2, and reproduced it again with React Router 7.14.2 and Vite 7.3.1. The integration test above uses the versions from this repo checkout.

The failing test creates multiple small Framework Mode apps and calls Vite's resolveConfig() for their Vite configs at the same time.

The branch has two cases:

  • multiple apps with a mix of manual route config and flatRoutes()
  • multiple apps where all route configs use flatRoutes()

Both fail because route files from one app are resolved under another app's appDirectory.

I also checked a control case locally: concurrent apps that use only manual route() config passed. The failure seems tied to flatRoutes() reading implicit app-directory state.

System Info

System:
    OS: Linux 6.8 Ubuntu 24.04.4 LTS 24.04.4 LTS (Noble Numbat)
    CPU: (16) x64 Common KVM processor
    Memory: 18.74 GB / 31.34 GB
    Container: Yes
    Shell: 5.9 - /bin/zsh
Binaries:
    Node: 22.21.1 - /home/coder/.local/share/mise/installs/node/22.21.1/bin/node
    npm: 10.9.4 - /home/coder/.local/share/mise/installs/node/22.21.1/bin/npm
    pnpm: 9.10.0 - /home/coder/.local/share/mise/installs/node/22.21.1/bin/pnpm
npmPackages:
    vite: ^6.3.0 => 6.4.1
    react-router: 7.14.2
    @react-router/dev: 7.14.2
    @react-router/fs-routes: 7.14.2

Used Package Manager

pnpm

Expected Behavior

Each React Router Vite plugin instance should resolve routes for its own app only. Concurrent resolveConfig() calls should not make one app read another app's route config or route files.

Actual Behavior

Route state can leak between apps when their Vite configs are resolved concurrently and at least one app uses flatRoutes().

The failing test shows errors like:

Error: ENOENT: no such file or directory, open '.../<app-a>/app/routes/dashboard.tsx'
Error: ENOENT: no such file or directory, open '.../<app-b>/app/routes/login.tsx'

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions