Skip to content

tanstackRouterBrowserTracingIntegration: pageload transaction name ignores router basepath #23253

Description

@maastrich

Summary

tanstackRouterBrowserTracingIntegration names the pageload span by matching the raw window.location.pathname, which still contains the router basepath. router.matchRoutes(pathname) expects a router-relative pathname (TanStack applies the basepath as a URL rewrite in parseLocation, so latestLocation.pathname never contains it). With a non-/ basepath the pageload transaction is therefore matched against the wrong path.

The navigation / onResolved paths are correct — they use toLocation.pathname, which is already basepath-stripped. Only the initial pageload name is affected.

Code

packages/react/src/tanstackrouter.ts (still present in 10.70.0):

const initialWindowLocation = WINDOW.location;
if (instrumentPageLoad && initialWindowLocation) {
  const routeMatch = resolveRouteMatch(
    initialWindowLocation.pathname, // <-- includes basepath
    castRouterInstance.options.parseSearch(initialWindowLocation.search),
  );
  ...
}

vs.

const resolvedMatch = resolveRouteMatch(toLocation.pathname, toLocation.search); // <-- basepath-stripped

Reproduction

const router = createRouter({
  basepath: "/app",
  routeTree, // contains '/reports/$id' and a catch-all '/$a/$b/$c'
});

Load /app/reports/123.

  • Expected pageload transaction: /reports/$id
  • Actual: /$a/$b/$c, with url.path.params.a = "app"

getMatchedRoutes matches fuzzily, so the extra basepath segments get absorbed by any sufficiently dynamic route and a plausible-but-wrong route id wins. When no route absorbs them you instead fall back to source: "url" with the raw pathname as the name.

This is not just cosmetic: the scope transaction is set when the pageload span starts, and the later span.updateName() in onResolved does not rewrite it — so error events keep the wrong transaction/culprit for the whole page lifetime, including errors thrown long after load.

Suggested fix

Strip router.basepath from initialWindowLocation.pathname before calling resolveRouteMatch (only when it is a real prefix followed by / or end of string).

Versions

  • @sentry/react 10.69.0 and 10.70.0
  • @tanstack/react-router 1.170.x, @tanstack/router-core 1.171.x

Workaround

Pass the integration a proxy of the router whose matchRoutes strips the basepath when given a string.

Metadata

Metadata

Assignees

Projects

Status
No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions