Skip to content

fix(tracing): Skip duplicate navigation span from withAnchor POP_TO - #6439

Merged
antonis merged 10 commits into
mainfrom
fix/duplicate-popto-navigation-span-6434
Jul 28, 2026
Merged

fix(tracing): Skip duplicate navigation span from withAnchor POP_TO#6439
antonis merged 10 commits into
mainfrom
fix/duplicate-popto-navigation-span-6434

Conversation

@antonis

@antonis antonis commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

📢 Type of change

  • Bugfix
  • New feature
  • Enhancement
  • Refactoring

📜 Description

The fix skips starting a navigation span for a POP_TO whose target is the route we are already on

💡 Motivation and Context

Fixes #6434

💚 How did you test it?

CI, Manual

📝 Checklist

  • I added tests to verify changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • All tests passing.
  • Public API changes reviewed by another Mobile SDK team member or implemented according to the develop docs spec.
  • No breaking changes.

🔮 Next steps

…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>
@antonis
antonis force-pushed the fix/duplicate-popto-navigation-span-6434 branch from 864ccd2 to 2dd9cc9 Compare July 10, 2026 12:28
@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Semver Impact of This PR

None (no version bump detected)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


  • fix(tracing): Skip duplicate navigation span from withAnchor POP_TO by antonis in #6439
  • feat(tracing): Add check and download timing spans to Expo Updates listener by antonis in #6430
  • fix(tracing): Skip duplicate navigation span from withAnchor POP_TO by antonis in #6439
  • test(e2e): Assert TTID/TTFD spans share their navigation transaction's trace and parent span by antonis in #6530
  • chore(deps): add sharp ^0.35.0 resolution (dev-only advisory) by antonis in #6525
  • chore(deps): add body-parser ^2.3.0 resolution (dev-only advisory) by antonis in #6524
  • chore(deps): add morgan ^1.11.0 resolution (dev-only advisory) by antonis in #6523
  • chore(deps): bump postcss to ^8.5.18 (dev-only advisory) by antonis in #6522
  • chore(deps): bump brace-expansion 5.x to ^5.0.8 (dev-only advisory) by antonis in #6521
  • ci: Disable yarn age gate when bumping first-party @sentry deps by antonis in #6513
  • feat(core): Attach TurboModule breakdown to active spans on spanEnd by alwx in #6478
  • feat(core): Export instrumentStateGraph and deprecate instrumentLangGraph by antonis in #6520
  • chore(deps): bump the codeql-action group across 1 directory with 3 updates by dependabot in #6517
  • chore(deps): bump ruby/setup-ruby from 1.319.0 to 1.321.0 by dependabot in #6518
  • chore(deps): bump actions/checkout from 7.0.0 to 7.0.1 by dependabot in #6519
  • chore(deps): update JavaScript SDK to v10.68.0 by github-actions in #6516
  • chore(deps): bump tar from 7.5.20 to 7.5.21 by dependabot in #6515
  • chore(deps): bump lerna to ^9.0.7 to resolve remaining dev-tooling advisories by antonis in #6499
  • chore(deps): Migrate to @sentry/bundler-plugins by antonis in #6501
  • chore: update changelog warning with fix version by antonis in #6509
  • chore(deps): bump actions/setup-node from 6.4.0 to 7.0.0 by dependabot in #6463
  • chore(deps): bump json from 2.17.1.2 to 2.19.9 in /performance-tests by dependabot in #6512
  • chore(deps): update CLI to v3.6.2 by github-actions in #6511
  • chore(deps): update Sentry Android Gradle Plugin to v6.16.0 by github-actions in #6508

Plus 1 more


🤖 This preview updates automatically when you update the PR.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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.

@antonis antonis added the ready-to-merge Triggers the full CI test suite label Jul 10, 2026
@sentry

sentry Bot commented Jul 10, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
Sentry RN io.sentry.reactnative.sample 8.20.0 (100) Release

⚙️ sentry-react-native Build Distribution Settings

@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

iOS (legacy) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 3853.19 ms 1221.77 ms -2631.42 ms
Size 4.98 MiB 6.55 MiB 1.58 MiB

Baseline results on branch: main

Startup times

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

@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Android (legacy) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 514.93 ms 559.98 ms 45.05 ms
Size 49.74 MiB 55.37 MiB 5.63 MiB

Baseline results on branch: main

Startup times

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

@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Android (new) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 436.43 ms 459.94 ms 23.51 ms
Size 49.74 MiB 55.37 MiB 5.63 MiB

Baseline results on branch: main

Startup times

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

@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

iOS (new) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 3838.16 ms 1220.34 ms -2617.81 ms
Size 4.98 MiB 6.55 MiB 1.58 MiB

Baseline results on branch: main

Startup times

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

@antonis antonis left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marking as blocked in favour of #6472 for now. If the later lands I'll close this

antonis and others added 2 commits July 24, 2026 12:29
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>
Comment thread packages/core/src/js/tracing/reactnavigation.ts
Comment thread packages/core/src/js/tracing/reactnavigation.ts
- 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>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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.

Comment thread packages/core/test/tracing/reactnavigation.test.ts
…#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>
@antonis
antonis marked this pull request as ready for review July 24, 2026 12:42

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ 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.

Comment thread packages/core/src/js/tracing/reactnavigation.ts
…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>
@antonis antonis removed the Blocked label Jul 24, 2026

@lucas-zimerman lucas-zimerman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@antonis
antonis merged commit b2c78ca into main Jul 28, 2026
94 checks passed
@antonis
antonis deleted the fix/duplicate-popto-navigation-span-6434 branch July 28, 2026 14:32
@github-actions

Copy link
Copy Markdown
Contributor
Fails
🚫 Please consider adding a changelog entry for the next release.

Instructions and example for changelog

Please add an entry to CHANGELOG.md to the "Unreleased" section. Make sure the entry includes this PR's number.

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 #skip-changelog to the PR description or adding a skip-changelog label.

Generated by 🚫 dangerJS against c4f0fad

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Triggers the full CI test suite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

withAnchor's internal POP_TO bookkeeping dispatch creates a spurious duplicate navigation span

2 participants