Repository navigation
[Android] Unbounded ui.load.initial_display end timestamp inflates navigation transaction duration to days when ScreenStackFragment draws late #6208
Description
Filed by Sentry Support on behalf of a customer. Internal reference: Intercom conversation.
What React Native libraries do you use?
React Navigation, Hermes, RN New Architecture, Expo (mobile only), Expo Application Services (EAS)
Are you using sentry.io or on-premise?
sentry.io (SaaS)
Are you using any other error monitoring solution alongside Sentry?
No
@sentry/react-native SDK Version
8.2.0. Also reproduces against the current develop branch.
How does your development environment look like?
React Native: 0.83.6
Hermes: 0.14.1 (enabled)
New Architecture: Fabric + Turbo Modules (enabled)
Expo: yes
Target: Android (observed in production)
Sentry.init()
Sentry.init({
// ...
integrations: [
Sentry.reactNativeTracingIntegration(),
Sentry.reactNavigationIntegration({
enableTimeToInitialDisplay: true,
useDispatchedActionData: true,
}),
],
});Steps to Reproduce
Navigation hierarchy:
NavigationContainer
└── Stack
└── Tab
└── Stack
└── ScreenA (initial route)
- Cold start the app on Android with the navigation hierarchy above and
enableTimeToInitialDisplay: trueonreactNavigationIntegration. - Navigate into a sibling screen inside the inner stack so
ScreenA'sScreenStackFragmentview is destroyed orfreezeOnBlur'd but the fragment remains cached behind the tab. - Background the app. With Hermes on Android the JS thread is suspended.
- Foreground the app some time later (minutes to days).
- POP back to
ScreenA. The fragment view is recreated,RNSentryReactFragmentLifecycleTracer.onFragmentViewCreatedre-attaches itsScreenAppearEventlistener, the event fires, andFirstDrawDoneListener.registerForNextDrawcaptures the current draw timestamp intoRNSentryTimeToDisplayagainst the currently-active span ID. - The JS-side idle navigation span finishes with
sentry.idle_span_finish_reason: idleTimeout. timeToDisplayIntegration.processEventreads the stored TTID viapopTimeToDisplayForand unconditionally extendsevent.timestamp = max(ttid.timestamp, ttfd.timestamp, event.timestamp).
Expected Result
- The
ui.load.initial_displayend timestamp is bounded. If the captured TTID is past a sensible deadline relative tostart_timestamp, the SDK either drops the TTID, marks itdeadline_exceeded, or refuses to extendevent.timestampwith it. - The root
navigationtransaction duration reflects the actual screen render time, not the wall-clock elapsed since navigation started.
Actual Result
The root navigation transaction is sent with a duration of hours or days. The captured TTID has the same start/end as the root, and event.timestamp is extended to match the TTID end. Trace excerpt:
{
"op": "navigation",
"start_timestamp": 1778936730.088075,
"timestamp": 1779346256.41,
"data": {
"sentry.idle_span_finish_reason": "idleTimeout",
"navigation.action_type": "POP",
"route.name": "ScreenA"
}
}{
"op": "ui.load.initial_display",
"description": "com.swmansion.rnscreens.ScreenStackFragment initial display",
"origin": "auto.ui.time_to_display",
"start_timestamp": 1778936730.088075,
"timestamp": 1779346256.41
}The navigation.processing child closed at start + 29 ms. All http.client children closed within roughly 1 s. Only the TTID is pathological. Observed at production scale on Sentry SaaS as a small but non-trivial fraction (well under 1%) of navigation transactions exceeding 1 hour duration, 100% on Android, concentrated on screens behind a Stack > Tab > Stack shape.
Workaround
Sentry.init({
// ...
beforeSendTransaction(event) {
const start = event.start_timestamp ?? 0;
const end = event.timestamp ?? 0;
if (event.contexts?.trace?.op === 'navigation' && end - start > 60) {
return null;
}
return event;
},
});Safe on 8.2.0 and on develop, no effect on healthy traces, immediately stops inflated transactions from polluting Sentry aggregates and alerts.
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsNo status
Activity
linear-code commentedon May 22, 2026
RN-654
antonis commentedon May 22, 2026
Thank you for the report 🙇 We are working on a fix in #6210
We will iterate here once the changes are shipped.
fix(tracing): Bound TTID/TTFD to prevent inflated transactions (#6210)
github-actions commentedon May 28, 2026
A PR closing this issue has just been released 🚀
This issue was referenced by PR #6210, which was included in the 8.13.0 release.