Skip to content

Commit 5901e70

Browse files
authored
fix(react,solid,vue): Fix parametrization behavior for non-matched routes (#18735)
Our e2e tests started breaking around the `1.142.x` release of tanstack router, we ended up hard-pinning the version to `1.141.8`. The failures revealed a real behavioral change of matches tanstack router returns when attempting to match a non-existing route. Previously the matches would be an empty array, but we now get a `__root__` match. The fix involves checking if the last match is `__root__` and falling back to `url` for `sentry.source` attributes. Closes: #18672
1 parent 31cc183 commit 5901e70

9 files changed

Lines changed: 60 additions & 40 deletions

File tree

dev-packages/e2e-tests/test-applications/solid-tanstack-router/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"dependencies": {
1616
"@sentry/solid": "latest || *",
1717
"@tailwindcss/vite": "^4.0.6",
18-
"@tanstack/solid-router": "1.141.8",
18+
"@tanstack/solid-router": "^1.141.8",
1919
"@tanstack/solid-router-devtools": "^1.132.25",
2020
"@tanstack/solid-start": "^1.132.25",
2121
"solid-js": "^1.9.5",

dev-packages/e2e-tests/test-applications/solid-tanstack-router/src/main.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const indexRoute = createRoute({
3939

4040
const postsRoute = createRoute({
4141
getParentRoute: () => rootRoute,
42-
path: 'posts/',
42+
path: 'posts',
4343
});
4444

4545
const postIdRoute = createRoute({

dev-packages/e2e-tests/test-applications/tanstack-router/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
},
1414
"dependencies": {
1515
"@sentry/react": "latest || *",
16-
"@tanstack/react-router": "1.64.0",
16+
"@tanstack/react-router": "^1.64.0",
1717
"react": "^18.2.0",
1818
"react-dom": "^18.2.0"
1919
},

dev-packages/e2e-tests/test-applications/tanstack-router/src/main.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const indexRoute = createRoute({
4141

4242
const postsRoute = createRoute({
4343
getParentRoute: () => rootRoute,
44-
path: 'posts/',
44+
path: 'posts',
4545
});
4646

4747
const postIdRoute = createRoute({

dev-packages/e2e-tests/test-applications/vue-tanstack-router/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
},
1515
"dependencies": {
1616
"@sentry/vue": "latest || *",
17-
"@tanstack/vue-router": "1.141.8",
17+
"@tanstack/vue-router": "^1.141.8",
1818
"vue": "^3.4.15"
1919
},
2020
"devDependencies": {

dev-packages/e2e-tests/test-applications/vue-tanstack-router/src/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const indexRoute = createRoute({
1919

2020
const postsRoute = createRoute({
2121
getParentRoute: () => rootRoute,
22-
path: 'posts/',
22+
path: 'posts',
2323
});
2424

2525
const postIdRoute = createRoute({

packages/react/src/tanstackrouter.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,17 @@ export function tanstackRouterBrowserTracingIntegration(
4949
);
5050

5151
const lastMatch = matchedRoutes[matchedRoutes.length - 1];
52+
// If we only match __root__, we ended up not matching any route at all, so
53+
// we fall back to the pathname.
54+
const routeMatch = lastMatch?.routeId !== '__root__' ? lastMatch : undefined;
5255

5356
startBrowserTracingPageLoadSpan(client, {
54-
name: lastMatch ? lastMatch.routeId : initialWindowLocation.pathname,
57+
name: routeMatch ? routeMatch.routeId : initialWindowLocation.pathname,
5558
attributes: {
5659
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'pageload',
5760
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.react.tanstack_router',
58-
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: lastMatch ? 'route' : 'url',
59-
...routeMatchToParamSpanAttributes(lastMatch),
61+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeMatch ? 'route' : 'url',
62+
...routeMatchToParamSpanAttributes(routeMatch),
6063
},
6164
});
6265
}
@@ -74,40 +77,44 @@ export function tanstackRouterBrowserTracingIntegration(
7477
return;
7578
}
7679

77-
const onResolvedMatchedRoutes = castRouterInstance.matchRoutes(
80+
const matchedRoutesOnBeforeNavigate = castRouterInstance.matchRoutes(
7881
onBeforeNavigateArgs.toLocation.pathname,
7982
onBeforeNavigateArgs.toLocation.search,
8083
{ preload: false, throwOnError: false },
8184
);
8285

83-
const onBeforeNavigateLastMatch = onResolvedMatchedRoutes[onResolvedMatchedRoutes.length - 1];
86+
const onBeforeNavigateLastMatch = matchedRoutesOnBeforeNavigate[matchedRoutesOnBeforeNavigate.length - 1];
87+
const onBeforeNavigateRouteMatch =
88+
onBeforeNavigateLastMatch?.routeId !== '__root__' ? onBeforeNavigateLastMatch : undefined;
8489

8590
const navigationLocation = WINDOW.location;
8691
const navigationSpan = startBrowserTracingNavigationSpan(client, {
87-
name: onBeforeNavigateLastMatch ? onBeforeNavigateLastMatch.routeId : navigationLocation.pathname,
92+
name: onBeforeNavigateRouteMatch ? onBeforeNavigateRouteMatch.routeId : navigationLocation.pathname,
8893
attributes: {
8994
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',
9095
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react.tanstack_router',
91-
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: onBeforeNavigateLastMatch ? 'route' : 'url',
96+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: onBeforeNavigateRouteMatch ? 'route' : 'url',
9297
},
9398
});
9499

95100
// In case the user is redirected during navigation we want to update the span with the right value.
96101
const unsubscribeOnResolved = castRouterInstance.subscribe('onResolved', onResolvedArgs => {
97102
unsubscribeOnResolved();
98103
if (navigationSpan) {
99-
const onResolvedMatchedRoutes = castRouterInstance.matchRoutes(
104+
const matchedRoutesOnResolved = castRouterInstance.matchRoutes(
100105
onResolvedArgs.toLocation.pathname,
101106
onResolvedArgs.toLocation.search,
102107
{ preload: false, throwOnError: false },
103108
);
104109

105-
const onResolvedLastMatch = onResolvedMatchedRoutes[onResolvedMatchedRoutes.length - 1];
110+
const onResolvedLastMatch = matchedRoutesOnResolved[matchedRoutesOnResolved.length - 1];
111+
const onResolvedRouteMatch =
112+
onResolvedLastMatch?.routeId !== '__root__' ? onResolvedLastMatch : undefined;
106113

107-
if (onResolvedLastMatch) {
108-
navigationSpan.updateName(onResolvedLastMatch.routeId);
114+
if (onResolvedRouteMatch) {
115+
navigationSpan.updateName(onResolvedRouteMatch.routeId);
109116
navigationSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');
110-
navigationSpan.setAttributes(routeMatchToParamSpanAttributes(onResolvedLastMatch));
117+
navigationSpan.setAttributes(routeMatchToParamSpanAttributes(onResolvedRouteMatch));
111118
}
112119
}
113120
});

packages/solid/src/tanstackrouter.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,17 @@ export function tanstackRouterBrowserTracingIntegration<R extends AnyRouter>(
4848
);
4949

5050
const lastMatch = matchedRoutes[matchedRoutes.length - 1];
51+
// If we only match __root__, we ended up not matching any route at all, so
52+
// we fall back to the pathname.
53+
const routeMatch = lastMatch?.routeId !== '__root__' ? lastMatch : undefined;
5154

5255
startBrowserTracingPageLoadSpan(client, {
53-
name: lastMatch ? lastMatch.routeId : initialWindowLocation.pathname,
56+
name: routeMatch ? routeMatch.routeId : initialWindowLocation.pathname,
5457
attributes: {
5558
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'pageload',
5659
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.solid.tanstack_router',
57-
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: lastMatch ? 'route' : 'url',
58-
...routeMatchToParamSpanAttributes(lastMatch),
60+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeMatch ? 'route' : 'url',
61+
...routeMatchToParamSpanAttributes(routeMatch),
5962
},
6063
});
6164
}
@@ -73,40 +76,44 @@ export function tanstackRouterBrowserTracingIntegration<R extends AnyRouter>(
7376
return;
7477
}
7578

76-
const onResolvedMatchedRoutes = router.matchRoutes(
79+
const matchedRoutesOnBeforeNavigate = router.matchRoutes(
7780
onBeforeNavigateArgs.toLocation.pathname,
7881
onBeforeNavigateArgs.toLocation.search,
7982
{ preload: false, throwOnError: false },
8083
);
8184

82-
const onBeforeNavigateLastMatch = onResolvedMatchedRoutes[onResolvedMatchedRoutes.length - 1];
85+
const onBeforeNavigateLastMatch = matchedRoutesOnBeforeNavigate[matchedRoutesOnBeforeNavigate.length - 1];
86+
const onBeforeNavigateRouteMatch =
87+
onBeforeNavigateLastMatch?.routeId !== '__root__' ? onBeforeNavigateLastMatch : undefined;
8388

8489
const navigationLocation = WINDOW.location;
8590
const navigationSpan = startBrowserTracingNavigationSpan(client, {
86-
name: onBeforeNavigateLastMatch ? onBeforeNavigateLastMatch.routeId : navigationLocation.pathname,
91+
name: onBeforeNavigateRouteMatch ? onBeforeNavigateRouteMatch.routeId : navigationLocation.pathname,
8792
attributes: {
8893
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',
8994
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.solid.tanstack_router',
90-
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: onBeforeNavigateLastMatch ? 'route' : 'url',
95+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: onBeforeNavigateRouteMatch ? 'route' : 'url',
9196
},
9297
});
9398

9499
// In case the user is redirected during navigation we want to update the span with the right value.
95100
const unsubscribeOnResolved = router.subscribe('onResolved', onResolvedArgs => {
96101
unsubscribeOnResolved();
97102
if (navigationSpan) {
98-
const onResolvedMatchedRoutes = router.matchRoutes(
103+
const matchedRoutesOnResolved = router.matchRoutes(
99104
onResolvedArgs.toLocation.pathname,
100105
onResolvedArgs.toLocation.search,
101106
{ preload: false, throwOnError: false },
102107
);
103108

104-
const onResolvedLastMatch = onResolvedMatchedRoutes[onResolvedMatchedRoutes.length - 1];
109+
const onResolvedLastMatch = matchedRoutesOnResolved[matchedRoutesOnResolved.length - 1];
110+
const onResolvedRouteMatch =
111+
onResolvedLastMatch?.routeId !== '__root__' ? onResolvedLastMatch : undefined;
105112

106-
if (onResolvedLastMatch) {
107-
navigationSpan.updateName(onResolvedLastMatch.routeId);
113+
if (onResolvedRouteMatch) {
114+
navigationSpan.updateName(onResolvedRouteMatch.routeId);
108115
navigationSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');
109-
navigationSpan.setAttributes(routeMatchToParamSpanAttributes(onResolvedLastMatch));
116+
navigationSpan.setAttributes(routeMatchToParamSpanAttributes(onResolvedRouteMatch));
110117
}
111118
}
112119
});

packages/vue/src/tanstackrouter.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,22 @@ export function tanstackRouterBrowserTracingIntegration<R extends AnyRouter>(
4343
if (instrumentPageLoad && initialWindowLocation) {
4444
const matchedRoutes = router.matchRoutes(
4545
initialWindowLocation.pathname,
46-
4746
router.options.parseSearch(initialWindowLocation.search),
4847
{ preload: false, throwOnError: false },
4948
);
5049

5150
const lastMatch = matchedRoutes[matchedRoutes.length - 1];
51+
// If we only match __root__, we ended up not matching any route at all, so
52+
// we fall back to the pathname.
53+
const routeMatch = lastMatch?.routeId !== '__root__' ? lastMatch : undefined;
5254

5355
startBrowserTracingPageLoadSpan(client, {
54-
name: lastMatch ? lastMatch.routeId : initialWindowLocation.pathname,
56+
name: routeMatch ? routeMatch.routeId : initialWindowLocation.pathname,
5557
attributes: {
5658
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'pageload',
5759
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.vue.tanstack_router',
58-
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: lastMatch ? 'route' : 'url',
59-
...routeMatchToParamSpanAttributes(lastMatch),
60+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeMatch ? 'route' : 'url',
61+
...routeMatchToParamSpanAttributes(routeMatch),
6062
},
6163
});
6264
}
@@ -87,18 +89,20 @@ export function tanstackRouterBrowserTracingIntegration<R extends AnyRouter>(
8789
);
8890

8991
const onBeforeNavigateLastMatch = onResolvedMatchedRoutes[onResolvedMatchedRoutes.length - 1];
92+
const onBeforeNavigateRouteMatch =
93+
onBeforeNavigateLastMatch?.routeId !== '__root__' ? onBeforeNavigateLastMatch : undefined;
9094

9195
const navigationLocation = WINDOW.location;
9296
const navigationSpan = startBrowserTracingNavigationSpan(client, {
93-
name: onBeforeNavigateLastMatch
94-
? onBeforeNavigateLastMatch.routeId
97+
name: onBeforeNavigateRouteMatch
98+
? onBeforeNavigateRouteMatch.routeId
9599
: // In SSR/non-browser contexts, WINDOW.location may be undefined, so fall back to the router's location
96100
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
97101
navigationLocation?.pathname || onBeforeNavigateArgs.toLocation.pathname,
98102
attributes: {
99103
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',
100104
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.vue.tanstack_router',
101-
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: onBeforeNavigateLastMatch ? 'route' : 'url',
105+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: onBeforeNavigateRouteMatch ? 'route' : 'url',
102106
},
103107
});
104108

@@ -116,11 +120,13 @@ export function tanstackRouterBrowserTracingIntegration<R extends AnyRouter>(
116120
);
117121

118122
const onResolvedLastMatch = onResolvedMatchedRoutes[onResolvedMatchedRoutes.length - 1];
123+
const onResolvedRouteMatch =
124+
onResolvedLastMatch?.routeId !== '__root__' ? onResolvedLastMatch : undefined;
119125

120-
if (onResolvedLastMatch) {
121-
navigationSpan.updateName(onResolvedLastMatch.routeId);
126+
if (onResolvedRouteMatch) {
127+
navigationSpan.updateName(onResolvedRouteMatch.routeId);
122128
navigationSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');
123-
navigationSpan.setAttributes(routeMatchToParamSpanAttributes(onResolvedLastMatch));
129+
navigationSpan.setAttributes(routeMatchToParamSpanAttributes(onResolvedRouteMatch));
124130
}
125131
}
126132
});

0 commit comments

Comments
 (0)