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.
Summary
tanstackRouterBrowserTracingIntegrationnames the pageload span by matching the rawwindow.location.pathname, which still contains the routerbasepath.router.matchRoutes(pathname)expects a router-relative pathname (TanStack applies the basepath as a URL rewrite inparseLocation, solatestLocation.pathnamenever contains it). With a non-/basepath the pageload transaction is therefore matched against the wrong path.The navigation /
onResolvedpaths are correct — they usetoLocation.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):vs.
Reproduction
Load
/app/reports/123./reports/$id/$a/$b/$c, withurl.path.params.a = "app"getMatchedRoutesmatches 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 tosource: "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()inonResolveddoes 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.basepathfrominitialWindowLocation.pathnamebefore callingresolveRouteMatch(only when it is a real prefix followed by/or end of string).Versions
@sentry/react10.69.0 and 10.70.0@tanstack/react-router1.170.x,@tanstack/router-core1.171.xWorkaround
Pass the integration a proxy of the router whose
matchRoutesstrips the basepath when given a string.