Skip to content

fix(android): Prevent duplicated breadcrumbs on tombstone-merged events - #5888

Open
lucas-zimerman wants to merge 1 commit into
getsentry:mainfrom
lucas-zimerman:lz/flutter-tombstone-dirt
Open

fix(android): Prevent duplicated breadcrumbs on tombstone-merged events#5888
lucas-zimerman wants to merge 1 commit into
getsentry:mainfrom
lucas-zimerman:lz/flutter-tombstone-dirt

Conversation

@lucas-zimerman

@lucas-zimerman lucas-zimerman commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

📜 Description

Tombstone-merged native crash events already carry their own breadcrumb history captured at crash time. ApplicationExitInfoEventProcessor.setBreadcrumbs() was unconditionally appending disk-persisted scope breadcrumbs on top, duplicating overlapping entries (navigation, device.event, ui.click, etc.).

💡 Motivation and Context

Root cause of getsentry/sentry-dart#3856TombstoneMerged events on Android showed duplicated breadcrumbs compared to the regular signalhandler event for the same crash.

ApplicationExitInfoEventProcessor backfills persisted scope data onto Backfillable events (ANR and Tombstone). Every other field it backfills only fills in what's missing, but setBreadcrumbs blindly addAll'd the persisted list even when the event already had its own breadcrumbs. ANR events never hit this branch (they always start breadcrumb-less), but Tombstone-merged events reuse the native SDK's own captured event, which already has breadcrumbs — so the persisted, overlapping list got appended on top.

Fix mirrors the existing guard in SentryClient.applyScope() for Cached native events: skip the backfill when the event already carries breadcrumbs.

Linear: JAVA-627, DART-429

💚 How did you test it?

  • Added a regression test simulating a tombstone-merged event (pre-existing breadcrumbs + overlapping persisted breadcrumbs) asserting no duplication.
  • Updated an existing test that had locked in the buggy merge-and-duplicate behavior.
  • ./gradlew :sentry-android-core:testReleaseUnitTest --tests "*ApplicationExitInfoEventProcessorTest*" — all 50 tests pass.
  • ./gradlew spotlessApply apiDump — clean, no public API surface changed (private method).

📝 Checklist

  • I added GH Issue ID & Linear ID
  • I added tests to verify the 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.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.
  • Public API changes reviewed by another Mobile SDK team member or implemented according to the develop docs spec.

🔮 Next steps

Open against getsentry/sentry-java once ready.

Tombstone-merged native crash events already carry their own
breadcrumb history from crash time; backfilling persisted scope
breadcrumbs on top of them duplicated entries. Skip the backfill
when the event already has breadcrumbs, matching the guard already
used for cached native events in SentryClient.applyScope().

Co-Authored-By: Claude <noreply@anthropic.com>
@lucas-zimerman

Copy link
Copy Markdown
Collaborator Author

The fix seems simple, and it kinda is, both capture event and add breadcrumbs are being asynchronously sent to the NDK layer, so at the end, they end up duplicated when checked.

Here is a sample event before the patch: https://sentry-sdks.sentry.io/issues/7652870323/events/8c52a48aa88c4060366c04557a092f4d/?project=5428562&referrer=discover-events-table
And one after: https://sentry-sdks.sentry.io/issues/7652870323/?project=5428562&query=is%3Aunresolved&referrer=issue-stream

Also since both observers on Native are async, I thought we would lose some breadcrumb, but by doing some testing on a 10ms loop, it seems like there were no missing breadcrumbs.
Example event with the breadcrumb loop before the changes: https://sentry-sdks.sentry.io/issues/7652870323/events/068f90dcbf0c4d6e6e24f160327e4919/?project=5428562&referrer=discover-events-table

Happy to do a sanity check on merging the breadcrumbs if necessary.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant