Skip to content

React Router transaction name has a double slash when lazyRouteManifest is used with a basename ending in / #25758

Open

Description

@seongwon030

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/react

SDK Version

11.9.0 (reproduced on develop at 7d1f14f; the same line is in 10.77.1)

Framework Version

react-router 7.18.3 and 6.30.4

Link to Sentry event

No response

Reproduction Example/SDK Setup

Sentry.init({
  dsn: '...',
  integrations: [
    Sentry.reactRouterV7BrowserTracingIntegration({
      useEffect: React.useEffect,
      useLocation,
      useNavigationType,
      createRoutesFromChildren,
      matchRoutes,
      enableAsyncRouteHandlers: true,
      lazyRouteManifest: ['/users/:id'],
    }),
  ],
  tracesSampleRate: 1,
});

const router = Sentry.wrapCreateBrowserRouterV7(createBrowserRouter)(
  [
    { path: '/', element: <Home /> },
    { path: '/users/:id', element: <User /> },
  ],
  { basename: '/app/' },
);

Steps to Reproduce

  1. Set up the integration with enableAsyncRouteHandlers: true and a lazyRouteManifest.
  2. Create the router with a basename that ends in /, e.g. /app/ or / (for example import.meta.env.BASE_URL in Vite).
  3. Open /app/users/123 and look at the pageload transaction name. Navigations behave the same.

Expected Result

/app/users/:id (and /users/:id for basename /) with source route, the same as with basename /app.

Actual Result

/app//users/:id for basename /app/, and //users/:id for basename /. Source is route, and this is the name that gets sent.

The manifest branch of resolveRouteNameAndSource prepends the basename as passed in:

// packages/react/src/reactrouter-compat-utils/utils.ts:372
return [(stripBasename ? '' : basename) + manifestMatch, 'route'];

On develop the router-match branch trims the trailing slash first (utils.ts:341 and :349, since #25639). The manifest branch has concatenated the raw basename since lazyRouteManifest was added. React Router accepts a basename with a trailing slash, and matchRouteManifest already handles it when stripping (route-manifest.test.ts, "handles basename with trailing slash"). Only the concatenation misses the trim.

The manifest is checked before route matching, so this happens for any route the manifest matches, lazy or not. I reproduced it through wrapCreateBrowserRouterV7, wrapCreateMemoryRouterV6, and the @sentry/react/react-router entry. It does not happen with stripBasename: true or with a basename without a trailing slash.

Additional Context

A one-line fix (trimSlash(basename) on that line) makes my repro tests pass, and the rest of the @sentry/react tests still pass with it. If this looks right to you, I'd be happy to open a PR with those tests.

Activity

  1. linear-code commented on Oct 27, 2026

    @linear-code
  2. self-assigned this
    on Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions