fix(tracing): Skip duplicate navigation span from withAnchor POP_TO - #6439
Conversation
…6434) Expo Router's `withAnchor` navigations can emit a second `POP_TO` dispatch to the destination route purely to stamp `initial: false` onto it. Since `startIdleNavigationSpan` runs on every `__unsafe_action__` dispatch and `POP_TO` was not filtered, this bookkeeping dispatch started a second idle navigation span that lingered until timeout and was sent as a spurious duplicate transaction (sometimes capturing in-flight HTTP/TTID children). Skip starting a navigation span for a `POP_TO` whose target is the route we are already on. The current route name is read from React Navigation's own `getCurrentRoute()` (raw name, same namespace as the action payload) rather than `latestRoute`, whose name may be rewritten by a route override provider such as Expo Router. Genuine `popTo`/`dismissTo` navigations to a different route are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
864ccd2 to
2dd9cc9
Compare
Semver Impact of This PR⚪ None (no version bump detected) 📋 Changelog PreviewThis is how your changes will appear in the changelog.
Plus 1 more 🤖 This preview updates automatically when you update the PR. |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 2dd9cc9. Configure here.
📲 Install BuildsAndroid
|
iOS (legacy) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 0a147b2+dirty | 3838.15 ms | 1221.94 ms | -2616.21 ms |
| 15d4514+dirty | 3840.17 ms | 1225.79 ms | -2614.38 ms |
| 5569641+dirty | 3839.22 ms | 1231.30 ms | -2607.91 ms |
| 3a829f0+dirty | 3839.76 ms | 1214.69 ms | -2625.06 ms |
| 4966363+dirty | 3854.04 ms | 1231.55 ms | -2622.50 ms |
| eb93136+dirty | 3843.09 ms | 1220.11 ms | -2622.98 ms |
| 0b1b5e3+dirty | 3823.96 ms | 1220.12 ms | -2603.84 ms |
| ca9d079+dirty | 3835.63 ms | 1218.68 ms | -2616.95 ms |
| 1e5d96d+dirty | 3851.45 ms | 1212.05 ms | -2639.41 ms |
| 5ee78d6+dirty | 3847.52 ms | 1224.27 ms | -2623.25 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 0a147b2+dirty | 4.98 MiB | 6.51 MiB | 1.53 MiB |
| 15d4514+dirty | 5.15 MiB | 6.70 MiB | 1.55 MiB |
| 5569641+dirty | 5.15 MiB | 6.67 MiB | 1.51 MiB |
| 3a829f0+dirty | 5.15 MiB | 6.70 MiB | 1.54 MiB |
| 4966363+dirty | 5.15 MiB | 6.68 MiB | 1.53 MiB |
| eb93136+dirty | 5.15 MiB | 6.69 MiB | 1.53 MiB |
| 0b1b5e3+dirty | 5.15 MiB | 6.70 MiB | 1.54 MiB |
| ca9d079+dirty | 5.15 MiB | 6.69 MiB | 1.53 MiB |
| 1e5d96d+dirty | 4.98 MiB | 6.46 MiB | 1.49 MiB |
| 5ee78d6+dirty | 5.15 MiB | 6.69 MiB | 1.53 MiB |
Previous results on branch: fix/duplicate-popto-navigation-span-6434
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 054da01+dirty | 3864.98 ms | 1226.74 ms | -2638.23 ms |
| 542850a+dirty | 3850.38 ms | 1235.64 ms | -2614.74 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 054da01+dirty | 4.98 MiB | 6.55 MiB | 1.57 MiB |
| 542850a+dirty | 4.98 MiB | 6.53 MiB | 1.55 MiB |
Android (legacy) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 5ca03f9+dirty | 423.30 ms | 467.00 ms | 43.70 ms |
| 1e5d96d+dirty | 519.43 ms | 543.62 ms | 24.19 ms |
| 21a1e70+dirty | 405.72 ms | 436.16 ms | 30.44 ms |
| 27d9693+dirty | 419.08 ms | 469.12 ms | 50.04 ms |
| 41d6254+dirty | 424.45 ms | 474.34 ms | 49.89 ms |
| 0a9e622+dirty | 420.73 ms | 464.83 ms | 44.10 ms |
| 7887847+dirty | 416.61 ms | 462.04 ms | 45.43 ms |
| e763471+dirty | 426.57 ms | 458.21 ms | 31.64 ms |
| 4953e94+dirty | 442.02 ms | 456.52 ms | 14.50 ms |
| 40c9884+dirty | 430.40 ms | 497.76 ms | 67.36 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 5ca03f9+dirty | 49.74 MiB | 55.26 MiB | 5.52 MiB |
| 1e5d96d+dirty | 49.74 MiB | 54.81 MiB | 5.07 MiB |
| 21a1e70+dirty | 49.74 MiB | 54.82 MiB | 5.07 MiB |
| 27d9693+dirty | 49.74 MiB | 55.09 MiB | 5.34 MiB |
| 41d6254+dirty | 48.30 MiB | 53.60 MiB | 5.30 MiB |
| 0a9e622+dirty | 49.74 MiB | 55.09 MiB | 5.34 MiB |
| 7887847+dirty | 49.74 MiB | 54.81 MiB | 5.07 MiB |
| e763471+dirty | 49.74 MiB | 54.85 MiB | 5.11 MiB |
| 4953e94+dirty | 43.75 MiB | 48.08 MiB | 4.33 MiB |
| 40c9884+dirty | 49.74 MiB | 55.09 MiB | 5.34 MiB |
Previous results on branch: fix/duplicate-popto-navigation-span-6434
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 054da01+dirty | 492.83 ms | 571.64 ms | 78.81 ms |
| 542850a+dirty | 431.73 ms | 494.18 ms | 62.45 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 054da01+dirty | 49.74 MiB | 55.36 MiB | 5.62 MiB |
| 542850a+dirty | 49.74 MiB | 55.26 MiB | 5.52 MiB |
Android (new) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 100ce80+dirty | 463.28 ms | 532.10 ms | 68.82 ms |
| 0bd8916+dirty | 400.15 ms | 442.72 ms | 42.57 ms |
| 5ca03f9+dirty | 412.83 ms | 459.40 ms | 46.57 ms |
| 5c1e987+dirty | 444.71 ms | 475.13 ms | 30.42 ms |
| 27d9693+dirty | 438.63 ms | 514.08 ms | 75.46 ms |
| 3b6e9f9+dirty | 442.39 ms | 486.44 ms | 44.05 ms |
| 0a9e622+dirty | 425.22 ms | 457.00 ms | 31.78 ms |
| 882f8ae+dirty | 408.19 ms | 435.86 ms | 27.67 ms |
| e763471+dirty | 538.31 ms | 574.44 ms | 36.13 ms |
| 40c9884+dirty | 453.76 ms | 478.98 ms | 25.22 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 100ce80+dirty | 48.30 MiB | 53.46 MiB | 5.15 MiB |
| 0bd8916+dirty | 48.30 MiB | 53.57 MiB | 5.26 MiB |
| 5ca03f9+dirty | 49.74 MiB | 55.26 MiB | 5.52 MiB |
| 5c1e987+dirty | 43.94 MiB | 48.94 MiB | 5.00 MiB |
| 27d9693+dirty | 49.74 MiB | 55.09 MiB | 5.34 MiB |
| 3b6e9f9+dirty | 48.30 MiB | 53.54 MiB | 5.23 MiB |
| 0a9e622+dirty | 49.74 MiB | 55.09 MiB | 5.34 MiB |
| 882f8ae+dirty | 48.30 MiB | 53.60 MiB | 5.29 MiB |
| e763471+dirty | 49.74 MiB | 54.85 MiB | 5.11 MiB |
| 40c9884+dirty | 49.74 MiB | 55.09 MiB | 5.34 MiB |
Previous results on branch: fix/duplicate-popto-navigation-span-6434
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 054da01+dirty | 431.04 ms | 493.28 ms | 62.24 ms |
| 542850a+dirty | 433.90 ms | 497.21 ms | 63.32 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 054da01+dirty | 49.74 MiB | 55.36 MiB | 5.62 MiB |
| 542850a+dirty | 49.74 MiB | 55.26 MiB | 5.52 MiB |
iOS (new) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 0a147b2+dirty | 3845.11 ms | 1230.81 ms | -2614.30 ms |
| 09a902f+dirty | 3847.65 ms | 1221.31 ms | -2626.34 ms |
| 88735e9+dirty | 3837.80 ms | 1216.39 ms | -2621.41 ms |
| 5a23c47+dirty | 3843.54 ms | 1226.05 ms | -2617.50 ms |
| 0bd8916+dirty | 3816.17 ms | 1215.05 ms | -2601.12 ms |
| 100ce80+dirty | 3843.57 ms | 1226.46 ms | -2617.12 ms |
| 1e5d96d+dirty | 3845.93 ms | 1222.51 ms | -2623.42 ms |
| 853723c+dirty | 3849.33 ms | 1221.07 ms | -2628.26 ms |
| f170ec3+dirty | 3844.74 ms | 1222.67 ms | -2622.07 ms |
| 68672fc+dirty | 3832.22 ms | 1228.29 ms | -2603.93 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 0a147b2+dirty | 4.98 MiB | 6.51 MiB | 1.53 MiB |
| 09a902f+dirty | 4.98 MiB | 6.46 MiB | 1.49 MiB |
| 88735e9+dirty | 4.98 MiB | 6.46 MiB | 1.49 MiB |
| 5a23c47+dirty | 4.98 MiB | 6.46 MiB | 1.49 MiB |
| 0bd8916+dirty | 5.15 MiB | 6.69 MiB | 1.53 MiB |
| 100ce80+dirty | 5.15 MiB | 6.67 MiB | 1.51 MiB |
| 1e5d96d+dirty | 4.98 MiB | 6.46 MiB | 1.49 MiB |
| 853723c+dirty | 5.15 MiB | 6.69 MiB | 1.53 MiB |
| f170ec3+dirty | 5.15 MiB | 6.69 MiB | 1.53 MiB |
| 68672fc+dirty | 5.15 MiB | 6.71 MiB | 1.55 MiB |
Previous results on branch: fix/duplicate-popto-navigation-span-6434
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 054da01+dirty | 3854.16 ms | 1218.84 ms | -2635.32 ms |
| 542850a+dirty | 3828.55 ms | 1220.92 ms | -2607.63 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 054da01+dirty | 4.98 MiB | 6.55 MiB | 1.57 MiB |
| 542850a+dirty | 4.98 MiB | 6.53 MiB | 1.55 MiB |
…avigation-span-6434
…avigation-span-6434
Replace the dispatch-time-only, leaf-name dedup with the more complete two-guard design from #6472, plus a refinement that closes a false-suppression regression both prior approaches shared. - Dispatch-time guard (`isRouteFocused`): skip a `POP_TO` whose target is already focused on the active route chain AND that carries the `withAnchor` marker (`params.initial === false`). Requiring the marker is what lets a genuine `popTo` to an earlier same-named route in the stack (e.g. `[id]` → `[id]`, different `route.key`) through, since those never carry `initial`. - State-change guard: discard a `POP_TO` span that landed on the same `route.key` (a bookkeeping dispatch that slipped past the dispatch-time filter, e.g. a nested payload name), unless a deep link claimed it. Keyed on `route.key`, so it never affects a navigation that changed the route. `applyPendingDeepLinkToSpan` now returns whether it attached, so the state-change guard can preserve deep-link-to-current-screen attribution. Co-authored-by: Cryptoteep <cryptoteep@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Preserve deep-link attribution on a same-route POP_TO: check the `taggedDeepLinkSpans` set instead of the just-attached result, so a span tagged earlier via the synchronous late-arrival listener is not discarded (revert `applyPendingDeepLinkToSpan` back to `void`). Reported by cursor bot. - End `navigationProcessingSpan` before dropping it in `_discardLatestTransaction` so the bookkeeping-discard path does not leave an unfinished span dangling. Reported by sentry bot. - Add a test that a same-route POP_TO carrying a deep link is kept. Co-authored-by: Cryptoteep <cryptoteep@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit afeba2a. Configure here.
…#6434) The test used `emitNavigationWithoutStateChange()`, whose payload-less NAVIGATE is rejected by the `!dispatchedRouteName` guard under `useDispatchedActionData: true`, so no in-flight span was ever created and the assertion was trivially true. Start a real in-flight navigation via a payloaded NAVIGATE dispatch (no state change) so the test genuinely exercises the focused-route POP_TO not tearing it down. Verified it fails when the dispatch-time guard is removed. Reported by warden bot. Co-authored-by: Cryptoteep <cryptoteep@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit a7204aa. Configure here.
…hedActionData (#6434) The two guards were keyed off `navigationActionType` / the span's action-type attribute, both only populated when `useDispatchedActionData` is enabled. That option defaults off for `expoRouterIntegration` and the Expo sample, so the duplicate POP_TO transaction still occurred on the default setup where the bug was reported (confirmed: 2 transactions with the flag off). Drive the dispatch-time guard off `actionType` (parsed unconditionally) and track the latest navigation span's action type in a closure variable for the state-change discard, so both guards work regardless of the flag. The span attribute stays flag-gated to avoid changing trace metadata for existing users. The guards remain narrow: guard 1 requires `params.initial === false` (only set by withAnchor), guard 2 only discards a same-route-key POP_TO (a no-op pop). Add a test asserting the default (flag-off) setup no longer creates the duplicate transaction. Co-authored-by: Cryptoteep <cryptoteep@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Instructions and example for changelogPlease add an entry to Example: ## Unreleased
### Fixes
- Skip duplicate navigation span from withAnchor POP_TO ([#6439](https://github.com/getsentry/sentry-react-native/pull/6439))If none of the above apply, you can opt out of this check by adding |

📢 Type of change
📜 Description
The fix skips starting a navigation span for a
POP_TOwhose target is the route we are already on💡 Motivation and Context
Fixes #6434
💚 How did you test it?
CI, Manual
📝 Checklist
sendDefaultPIIis enabled.🔮 Next steps