getsentry / getsentry/sentry-react-native

Fatal 'JavaCallback was already settled' from getNewScreenTimeToDisplay under rapid navigation (Android, Expo, new arch)

Geschlossen
#6,709 2 Kommentare 0 Reaktionen 1 zugewiesene Person Beansprucht von @antonis Auf GitHub ansehen
Bug React-Native
Vorherrschende Sprache
TypeScript
Sterne
1.8k
Forks
366
Ø Merge
1 T. 5 Std.
Gemergte PRs (30 T.)
93

Beschreibung

### OS

Android

### Platform

Hermes, New Architecture

### SDK Version

8.19.0

### React Native Version

0.85.3 (Expo SDK 56, expo-modules-core 56.0.19)

### Steps to Reproduce

Not deterministic — it is a race, but the shape that reproduces it in our production fleet:

1. `Sentry.init` with `reactNavigationIntegration({enableTimeToInitialDisplay: true})`, container registered via `registerNavigationContainer` (expo-router).
2. App with 4 native bottom tabs (`react-native-bottom-tabs`) sharing a header.
3. Switch tabs rapidly and/or push a modal right after a tab switch (our events consistently show a paywall modal being pushed immediately after navigation — breadcrumbs end with the new screen's mount logs).

### Expected Result

TTID measurement completes or is dropped silently when navigations race.

### Actual Result

Fatal crash reported through `onerror`:

```
Error: Non-js exception: JavaCallback was already settled. Cannot invoke it again
```

Event tags point at the SDK's own TurboModule call:

- `turbo_module.name: RNSentry`
- `turbo_module.method: getNewScreenTimeToDisplay`
- `mechanism: onerror`, `handled: no`, `level: fatal`, Hermes, Android 12–16

Volume: 23 users in 4 days in production (it likely existed longer — our DSN was broken before that, so the SDK could not report its own crash).

### Analysis

`reactnavigation.ts` (`updateLatestNavigationSpanWithCurrentRoute`) calls `NATIVE.getNewScreenTimeToDisplay()` on **every** navigation state change while `enableTimeToInitialDisplay` is enabled. The Android implementation appears to keep a single stored callback to be settled on the next frame; when two navigation state changes race, the same callback gets settled twice. On Expo (new architecture) the promise guard in `expo-modules-core` (`PromiseImpl` — "was already settled") turns the second settle into the fatal above.

No matching fix found in the changelog up to 8.26.0, and no existing issue mentions `getNewScreenTimeToDisplay`, so filing this one.

### Workaround

`enableTimeToInitialDisplay: false` removes the crashing path entirely (confirmed: the call is gated only by that option).

Beitragsleitfaden

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.