Skip to content

React Router transactions are not parameterized when the URL has a percent-encoded parameter #25638

Closed

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.8.0 (reproduced on develop at 67fed31; also present in 9.47.1)

Framework Version

React 19.2, react-router 7.18

Link to Sentry event

No response

Reproduction Example/SDK Setup

Sentry.init({
  dsn: '...',
  integrations: [Sentry.reactRouterBrowserTracingIntegration()],
  tracesSampleRate: 1,
});

const SentryRoutes = Sentry.wrapReactRouterRouting(Routes);

<BrowserRouter>
  <SentryRoutes>
    <Route path="/clubs/:clubId" element={<Club />} />
  </SentryRoutes>
</BrowserRouter>

Minimal failing test against develop (same setup as packages/react/test/react-router.test.tsx):

render(
  // what a browser's location.pathname holds for /clubs/한글
  <MemoryRouter initialEntries={['/clubs/%ED%95%9C%EA%B8%80']}>
    <SentryRoutes>
      <Route path="/clubs/:clubId" element={<div>Club</div>} />
    </SentryRoutes>
  </MemoryRouter>,
);

expect(getCurrentScope().getScopeData().transactionName).toEqual('/clubs/:clubId');
// Received: "/clubs/%ED%95%9C%EA%B8%80"

Steps to Reproduce

  1. Define a route with a dynamic segment, e.g. /clubs/:clubId.
  2. Open a URL whose parameter is not plain ASCII, e.g. /clubs/한글 (the browser stores it as /clubs/%ED%95%9C%EA%B8%80).
  3. Look at the pageload or navigation transaction name.

Expected Result

Transaction name /clubs/:clubId with sentry.segment.name.source: route, like for /clubs/abc.

Actual Result

Transaction name is the raw URL /clubs/%ED%95%9C%EA%B8%80 with source url, so every parameter value becomes its own transaction name. For descendant routes (<Routes> nested under a /* route) the raw URL is reported with source route.

Mechanism: React Router decodes the pathname before matching (decodePath, segment-wise decodeURIComponent), so RouteMatch.pathname / pathnameBase are decoded, while useLocation().pathname is still percent-encoded. getNormalizedName in packages/react/src/reactrouter-compat-utils/utils.ts compares the two with ===:

if (trimSlash(location.pathname) !== trimSlash(basename + branch.pathname)) {
  continue;
}

so no branch ever matches for such URLs. rebuildRoutePathFromAllRoutes and reconstructNameFromDescendantParent strip the decoded pathnameBase from the encoded pathname in the same way.

Additional Context

I have a fix with tests ready and will open a PR right after this issue.

Priority

Medium

Activity

  1. linear-code commented on Oct 22, 2026

    @linear-code
  2. moved this to Waiting for: Product Owner in GitHub Issues with 👀 3on Oct 22, 2026
  3. self-assigned this
    on Oct 22, 2026
  4. s1gr1d commented on Oct 23, 2026

    @s1gr1d
    Member

    Hello, thanks for your issue and the PR! I left a review

  5. moved this from Waiting for: Product Owner to No status in GitHub Issues with 👀 3on Oct 23, 2026
  6. github-actions commented on Oct 28, 2026

    @github-actions
    Contributor

    A PR closing this issue has just been released 🚀

    This issue was referenced by PR #25639, which was included in the 11.10.0 release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions