Environment
- Expo SDK 57
- React Native 0.86.2 (regression began after 0.85.3 → 0.86.0)
- Hermes on iOS
- Reproduced with @sentry/react-native 8.21.0 / @sentry/core 10.69.0
- Production regression was first observed with @sentry/react-native 8.16.0
- @sentry/react-native 8.22.0 still depends on the same @sentry/core 10.69.0
- tracesSampleRate: 1.0
- sentry.io SaaS
Summary
Transactions are processed, uploaded, and accepted by Sentry with HTTP 200, but their timestamps are backdated by the amount of time the Apple performance clock did not advance during system sleep.
New iOS traces therefore disappear from current Sentry time windows. In production this looked like an abrupt iOS tracing-volume drop immediately after upgrading to Expo SDK 57 / React Native 0.86.
This is related to #6510, but that report is scoped to structured logs and says tracing uses a guarded time-origin path. React Navigation and app-start transactions are also affected because span creation and completion use timestampInSeconds() directly.
Steps to reproduce
- Use Expo SDK 57 / React Native 0.86 on iOS with Hermes.
- Allow the device or simulator host to accumulate sleep time since boot.
- Initialize Sentry with tracesSampleRate: 1 and debug: true.
- Compare Date.now() with performance.timeOrigin + performance.now().
- Start a navigation or app-start transaction.
- Observe the native transport writing the envelope and receiving HTTP 200.
- Fetch the transaction by exact event ID through the Sentry API and compare dateReceived with startTimestamp.
Observed clocks
Date.now(): 1786036083636
performance.timeOrigin: 1784904816638.1536
performance.now(): 949785977.287708
timeOrigin + performance.now(): 1785854602615.4412
skew: 181481020.56 ms (~50.4 hours)
One transaction was accepted as:
dateReceived: 2026-08-06T17:08:10.006329Z
startTimestamp: 2026-08-04T14:43:24.963859Z
environment: development
os.name: iOS
clientSampleRate: 1.0
The event could be fetched by exact ID. It was absent from current trace views because it was indexed roughly 50 hours in the past.
Regression boundary
React Native 0.86 promoted Web Performance APIs to stable/default-on:
react/react-native@beccee2
Before that change, Sentry effectively fell back to Date.now() in our stable React Native runtime. Once performance.timeOrigin became available, @sentry/core selected the Performance-based clock.
Root cause
@sentry/core createUnixTimestampInSecondsFunc() selects the clock once and trusts performance.timeOrigin + performance.now() without validating it against wall-clock time.
React Native's Apple high-resolution timer uses mach_absolute_time(). That clock does not include system sleep, so the absolute timestamp drifts behind Date.now().
The same Core time module validates this relationship in getBrowserTimeOrigin(), but timestampInSeconds() does not use that validation.
Related Sentry issue: getsentry/sentry-javascript#2590
Expected result
New transactions should be indexed near their actual wall-clock time and appear in current trace windows after successful ingestion.
Actual result
Transactions are ingested successfully but indexed hours or days in the past. Reinstalling or restarting the app does not repair the system-boot-based clock skew.
Verified workaround
We patched @sentry/core so createUnixTimestampInSecondsFunc() consistently returns dateTimestampInSeconds() when navigator.product === "ReactNative".
With that JS-only patch, while the Performance clock remained ~50.4 hours behind, an app.start transaction was received and indexed at the current time:
dateReceived: 2026-08-06T17:20:04.665104Z
startTimestamp: 2026-08-06T17:19:39.070688Z
operation: app.start
os.name: iOS
clientSampleRate: 1.0
A dynamic sanity check with fallback to Date.now(), or an explicit React Native clock choice, should prevent traces from disappearing from current time queries.
Environment
Summary
Transactions are processed, uploaded, and accepted by Sentry with HTTP 200, but their timestamps are backdated by the amount of time the Apple performance clock did not advance during system sleep.
New iOS traces therefore disappear from current Sentry time windows. In production this looked like an abrupt iOS tracing-volume drop immediately after upgrading to Expo SDK 57 / React Native 0.86.
This is related to #6510, but that report is scoped to structured logs and says tracing uses a guarded time-origin path. React Navigation and app-start transactions are also affected because span creation and completion use timestampInSeconds() directly.
Steps to reproduce
Observed clocks
One transaction was accepted as:
The event could be fetched by exact ID. It was absent from current trace views because it was indexed roughly 50 hours in the past.
Regression boundary
React Native 0.86 promoted Web Performance APIs to stable/default-on:
react/react-native@beccee2
Before that change, Sentry effectively fell back to Date.now() in our stable React Native runtime. Once performance.timeOrigin became available, @sentry/core selected the Performance-based clock.
Root cause
@sentry/core createUnixTimestampInSecondsFunc() selects the clock once and trusts performance.timeOrigin + performance.now() without validating it against wall-clock time.
React Native's Apple high-resolution timer uses mach_absolute_time(). That clock does not include system sleep, so the absolute timestamp drifts behind Date.now().
The same Core time module validates this relationship in getBrowserTimeOrigin(), but timestampInSeconds() does not use that validation.
Related Sentry issue: getsentry/sentry-javascript#2590
Expected result
New transactions should be indexed near their actual wall-clock time and appear in current trace windows after successful ingestion.
Actual result
Transactions are ingested successfully but indexed hours or days in the past. Reinstalling or restarting the app does not repair the system-boot-based clock skew.
Verified workaround
We patched @sentry/core so createUnixTimestampInSecondsFunc() consistently returns dateTimestampInSeconds() when navigator.product === "ReactNative".
With that JS-only patch, while the Performance clock remained ~50.4 hours behind, an app.start transaction was received and indexed at the current time:
A dynamic sanity check with fallback to Date.now(), or an explicit React Native clock choice, should prevent traces from disappearing from current time queries.