Skip to content

fix(core): Order breadcrumbs by their own timestamp (JAVA-579) - #6097

Open
runningcode wants to merge 4 commits into
mainfrom
no/java-579-c7-breadcrumb-ordering
Open

runningcode wants to merge 4 commits into
mainfrom
no/java-579-c7-breadcrumb-ordering

Conversation

@runningcode

@runningcode runningcode commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

📜 Description

Breadcrumb.compareTo ordered breadcrumbs purely by a System.nanoTime() reading taken in the constructor. That reading is meaningful only for breadcrumbs created in the same process run, and two paths violate that:

  • Deserialized breadcrumbs. Breadcrumb.fromMap and Breadcrumb.Deserializer both go through the public Breadcrumb(Date) constructor, so a breadcrumb read back from disk or handed over by a hybrid SDK takes its tick at parse time. A breadcrumb recorded yesterday sorted as if it had just happened, and the order CombinedScopeView merges the three scopes into became parse order rather than recorded order.
  • Clones. The copy constructor also took a fresh tick, so Scope's breadcrumb cloning moved every copied breadcrumb to the end of the order.

This orders by the recorded timestamp instead, keeping the creation tick as the tie-breaker it was added for in #3355. Cloning also now carries the original's creationTick.

Separately, there was a second Comparator in SentryClient. This is now removed so that the Breadcrumb's compare method is the single source of truth.

💡 Motivation and Context

Audit finding §C7 from the clock-usage audit: a System.nanoTime() value was driving an ordering decision across a process boundary, where it carries no meaning.

💚 How did you test it?

Four unit tests in BreadcrumbTest, covering live breadcrumbs sharing a timestamp, both deserialization paths (fromMap and Breadcrumb.Deserializer), and clones.

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

Note for hybrid SDKs: breadcrumbs passed in via Breadcrumb.fromMap now sort by the timestamp they carry rather than by the moment they were handed over. That is the intended fix, but it does change the order hybrid breadcrumbs land in relative to native ones. Where a hybrid and a native breadcrumb share a millisecond, the hybrid one sorts after the native one, since it takes its tie-breaker at the moment it is handed over rather than when it was recorded.

🔮 Next steps

@linear-code

linear-code Bot commented Sep 11, 2026

Copy link
Copy Markdown

JAVA-579

@sentry

sentry Bot commented Sep 11, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
SDK Size io.sentry.tests.size 8.56.0 (1) release

⚙️ sentry-android Build Distribution Settings

@runningcode
runningcode force-pushed the no/java-579-c7-breadcrumb-ordering branch from 7f48517 to 95aa7c0 Compare September 14, 2026 09:55
@runningcode runningcode added the sanity-check PR needs a lightweight review for obvious issues label Sep 14, 2026
@runningcode
runningcode marked this pull request as ready for review September 14, 2026 09:59

@adinauer adinauer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should always fill in creationTick as otherwise we risk a different bug.

Comment thread sentry/src/main/java/io/sentry/Breadcrumb.java Outdated

@0xadam-brown 0xadam-brown left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A couple quick comments for your consideration, but no blockers save for responding to @adinauer's concern 👍

Comment thread sentry/src/test/java/io/sentry/BreadcrumbTest.kt
Comment thread sentry/src/main/java/io/sentry/Breadcrumb.java
runningcode and others added 3 commits September 15, 2026 13:32
Breadcrumb.compareTo ordered purely by a System.nanoTime() reading taken
in the constructor. A breadcrumb rebuilt from a serialized one — read
back from disk, or handed over by a hybrid SDK — got that reading at
parse time, so a breadcrumb recorded yesterday sorted as if it had just
happened, and the merged order in CombinedScopeView became parse order.
The clone constructor had the same problem: copying a breadcrumb moved
it to the end of the order.

Order by the recorded timestamp instead, and keep the creation tick only
as the tie-breaker it was added for in #3355, since timestamps are
millisecond-granular. A deserialized breadcrumb carries no tick, and a
clone carries the original's, so neither jumps position.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Always fill the tick and let the timestamp comparison carry the fix, so
ordering no longer depends on every caller using a stable sort.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@runningcode
runningcode force-pushed the no/java-579-c7-breadcrumb-ordering branch from ef6122a to dad065d Compare September 15, 2026 11:34
Comment thread sentry/src/main/java/io/sentry/Breadcrumb.java
SortBreadcrumbsByDate compared timestamps only, so ties fell through to
the sort's stability. Breadcrumb.compareTo now defines that same order
with a defined tie-breaker, leaving the comparator a weaker duplicate of
it and the codebase with two definitions of breadcrumb order.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comment thread sentry/src/main/java/io/sentry/SentryClient.java
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

sanity-check PR needs a lightweight review for obvious issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants