Skip to content

Commit d787022

Browse files
committed
Fix duplication
1 parent 2879390 commit d787022

File tree

1 file changed

+15
-7
lines changed

1 file changed

+15
-7
lines changed

packages/react/src/reactrouter-compat-utils/instrumentation.tsx

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ let _useLocation: UseLocation;
4848
let _useNavigationType: UseNavigationType;
4949
let _createRoutesFromChildren: CreateRoutesFromChildren;
5050
let _matchRoutes: MatchRoutes;
51+
52+
// Track the last created navigation span to prevent duplicates when router.subscribe fires multiple times
53+
let _lastCreatedNavigationSpanName: string | null = null;
5154
let _enableAsyncRouteHandlers: boolean = false;
5255

5356
const CLIENTS_WITH_INSTRUMENT_NAVIGATION = new WeakSet<Client>();
@@ -713,6 +716,7 @@ function wrapPatchRoutesOnNavigation(
713716
};
714717
}
715718

719+
// eslint-disable-next-line complexity
716720
export function handleNavigation(opts: {
717721
location: Location;
718722
routes: RouteObject[];
@@ -753,15 +757,21 @@ export function handleNavigation(opts: {
753757

754758
// If we're already in a navigation span, check if we should update its name
755759
if (isAlreadyInNavigationSpan && activeSpan) {
756-
const currentSource = spanJson?.data?.[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
757-
const shouldUpdate = shouldUpdateWildcardSpanName(currentName, currentSource, name, source);
760+
// Only update if the new name is better (doesn't have wildcards or is more complete)
761+
const shouldUpdate = currentName && transactionNameHasWildcard(currentName) && !transactionNameHasWildcard(name);
758762

759763
if (shouldUpdate) {
760764
activeSpan.updateName(name);
761765
activeSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source as 'route' | 'url' | 'custom');
762766
DEBUG_BUILD && debug.log(`[Tracing] Updated navigation span name from "${currentName}" to "${name}"`);
763767
}
764768
} else if (!isAlreadyInNavigationSpan) {
769+
// Prevent duplicate navigation spans when router.subscribe fires multiple times
770+
// with the same route information after a span completes
771+
if (_lastCreatedNavigationSpanName === name) {
772+
return;
773+
}
774+
765775
// Cross usage can result in multiple navigation spans being created without this check
766776
const navigationSpan = startBrowserTracingNavigationSpan(client, {
767777
name,
@@ -772,6 +782,9 @@ export function handleNavigation(opts: {
772782
},
773783
});
774784

785+
// Track this navigation span to prevent immediate duplicates
786+
_lastCreatedNavigationSpanName = name;
787+
775788
// Patch navigation span to handle early cancellation (e.g., document.hidden)
776789
if (navigationSpan) {
777790
patchNavigationSpanEnd(navigationSpan, location, routes, basename, allRoutes);
@@ -887,11 +900,6 @@ function shouldUpdateWildcardSpanName(
887900
return true;
888901
}
889902

890-
// Allow route-to-route updates if names are different (legitimate navigation)
891-
if (currentSource === 'route' && newSource === 'route' && currentName !== newName) {
892-
return true;
893-
}
894-
895903
// Otherwise, don't update (prevents route→url downgrade)
896904
return false;
897905
}

0 commit comments

Comments
 (0)