Skip to content

React Router v6 integration: allRoutes accumulates across independent/unrelated routers, causing incorrect transaction names #22782

Closed

Description

@masinette

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/react-router

SDK Version

10.68.0

Framework Version

No response

Link to Sentry event

No response

Reproduction Example/SDK Setup

Two independent router trees are each wrapped with Sentry's React Router
instrumentation (e.g. via withSentryReactRouterV6Routing /
wrapCreateBrowserRouter), mounted at different points in the app's
lifecycle, For example, one router for /foo/:fooId and a separate,
unrelated router for /bar/:barId.

// Router A
const RoutesA = () => (
  <SentryRoutes>
    <Route path="/foo/:fooId" element={<FooPage />} />
  </SentryRoutes>
);

// Router B, mounted separately/later
const RoutesB = () => (
  <SentryRoutes>
    <Route path="/bar/:barId" element={<BarPage />} />
  </SentryRoutes>
);

customer provided a full repro app. Link to that repo is included in internal Linear Issue to protect PII

Steps to Reproduce

  1. Mount/navigate within Router A at /foo/123: transaction is correctly
    named /foo/:fooId.
  2. Mount/navigate within Router B at /bar/456.
  3. Observe the transaction name for the /bar/456 navigation.

Expected Result

Transaction name: /bar/:barId

Actual Result

Transaction name is a hybrid/incorrect name such as /bar/:fooId

i.e. the static segment from Router B's path combined with the param
name from Router A's route.

Additional Context

Root cause (if I had to guess)

reactrouterv6-compat-utils.tsx accumulates every route object it has
ever seen into a module-level allRoutes Set, populated via
getChildRoutesRecursively on each wrapped <Routes>'s mount effect,
and never scoped to a router instance or cleared on unmount:

routes.forEach(route => {
  const extractedChildRoutes = getChildRoutesRecursively(route);
  extractedChildRoutes.forEach(r => {
    allRoutes.add(r);
  });
});

This was introduced to support descendant routes / multiple <Routes>
trees that are legitimately part of the same logical route tree (see
#14304). But because allRoutes has no isolation between genuinely
independent router instances, once two unrelated routers have each been
mounted once, matchRoutes/rebuildRoutePathFromAllRoutes operates on
the union of both, and can produce a name that mixes structure from one
router with param names from another.

Priority

React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it.

Activity

  1. linear-code commented on Jul 28, 2026

    @linear-code
  2. moved this to Waiting for: Product Owner in GitHub Issues with 👀 3on Jul 28, 2026
  3. vansh2408 commented on Jul 28, 2026

    @vansh2408

    /assign

  4. logaretm commented on Jul 28, 2026

    @logaretm
    Member

    Taking a look at this, it is not a trivial fix because the global module-level set was added to fix #14304 and each <Routes> descendant is only aware of its own route fragment.

    I think I can attempt reconstructing the full path and add that to the set instead for matching, will explore a couple of ideas.

  5. moved this from Waiting for: Product Owner to No status in GitHub Issues with 👀 3on Jul 28, 2026
  6. self-assigned this
    on Jul 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions