Repository navigation
Description
Problem
On iOS, <Sentry.TimeToInitialDisplay> and <Sentry.TimeToFullDisplay> silently stop working when an app builds React Native with RCT_REMOVE_LEGACY_COMPONENT_INTEROP=1.
RNSentryOnDrawReporter is a legacy RCTViewManager, so on the New Architecture it only exists through RN's legacy component interop layer. With the flag on, the component is not registered, UIManager.hasViewManagerConfig('RNSentryOnDrawReporter') returns false, and getRNSentryOnDrawReporter() falls back to a plain View. Nothing logs an error or warning.
The flag is opt-in since RN 0.88. RN states that it and RCT_REMOVE_LEGACY_MODULE_INTEROP will default to on in a future release (scripts/react_native_pods.rb).
Verification
Two Release builds of samples/react-native on RN 0.88.1, both with RN compiled from source (RCT_USE_PREBUILT_RNCORE=0), on an iPhone 16 Pro simulator. The flag was the only difference. Each run navigated through the Errors, Performance and Tracker screens.
| Default | RCT_REMOVE_LEGACY_COMPONENT_INTEROP=1 |
|
|---|---|---|
RNSentryOnDrawReporter registered |
Yes | No |
Tracker ui.load.initial_display |
manual.ui.time_to_display, 49 ms |
auto.ui.time_to_display, 597 ms |
ui.load.full_display on any screen |
Present (2066 ms on Tracker) | Missing |
time_to_full_display measurement |
Present | Missing |
Automatic TTID from the navigation integration keeps working. With only this flag on, the RNSentry module still loaded.
Not tested
- RN's prebuilt framework with this flag. RN warns the flag only prunes headers there, so the interop layer probably stays in.
RCT_REMOVE_LEGACY_MODULE_INTEROP, alone or together with the component flag. RN compiles out static module registration only when both are set, andRNSentryhas noios.modulesProvider. It may still resolve through the class-name fallback inRCTTurboModuleManager, but that needs a build to confirm.- Android.
RNSentryOnDrawReporterManageris also a legacy view manager, but RN has no matching opt-out flag there yet, anduseFabricInteropstill defaults to on.
Proposed fix
Port RNSentryOnDrawReporter to a real Fabric component and register it through ios.componentProvider in codegenConfig, as RNSentryReplayMask and RNSentryReplayUnmask already are. The legacy view manager has to stay for the Old Architecture.
Separately, confirm whether RNSentry needs a modulesProvider entry.
Acceptance criteria
-
<Sentry.TimeToInitialDisplay>and<Sentry.TimeToFullDisplay>record manual spans on iOS withRCT_REMOVE_LEGACY_COMPONENT_INTEROP=1 - Behavior is unchanged on the default New Architecture build and on the Old Architecture
- The
RNSentrymodule is verified with both interop removal flags on - Android is reviewed against the same removal path
Activity
linear-code commentedon Nov 10, 2026
RN-853
antonis commentedon Nov 11, 2026
Closing #7015 for now. The fix works, but the problem is opt-in today, and the fix relies on React Native internals that may change before the default flips. Notes for when we revisit this:
Current impact: low
RCT_REMOVE_LEGACY_COMPONENT_INTEROPis opt-in. It defaults to0in RN 0.88.1, in 0.89.0-rc.1 and on RNmain. An app is only affected when all of these are true:RCT_REMOVE_LEGACY_COMPONENT_INTEROP=1itselfRCT_USE_PREBUILT_RNCORE=0). Prebuilt binaries are the default, and there the flag probably only prunes headers, so interop stays in (not verified)<Sentry.TimeToInitialDisplay>/<Sentry.TimeToFullDisplay>. Automatic TTID from the navigation integration is unaffectedWhen this happens it fails silently: manual TTID/TTFD spans are missing and nothing is logged.
Future impact: higher
RN says both interop flags "will default to 1 in a future React Native release" (
scripts/react_native_pods.rb). No version is named.Module interop is the bigger risk. Testing for fix(ios): Keep manual time to display working without legacy interop #7015 showed that with both
RCT_REMOVE_LEGACY_COMPONENT_INTEROPandRCT_REMOVE_LEGACY_MODULE_INTEROPset, theRNSentrynative module doesn't load at all. That breaks the whole native SDK, not just time to display. A plainmodulesProviderentry crashes at launch, becauseRNSentrydoesn't declareNativeRNSentrySpecconformance. Declaring it is the likely fix.What fix(ios): Keep manual time to display working without legacy interop #7015 depended on, and could break before the flip:
#ifdef RCT_REMOVE_LEGACY_COMPONENT_INTEROPreaching our pod. If RN removes interop together with the macro, or the flip ships through prebuilt binaries without passing the macro to third-party pods, the registration compiles out.RN$LegacyInterop_UIManager_getConstantsglobal.react-native/Libraries/NativeComponent/NativeComponentRegistry, now that deep imports are deprecated, and registration throughRCTComponentViewFactoryin+load.Any of these changing would bring back the same silent failure, not a crash.
When we pick this up
ios.componentProvider(likeRNSentryReplayMask/Unmask) once interop is gone, so we don't rely on the macro or the global check.useFabricInteropstill defaults to on. Review it when one appears.#7015 (branch
fix/ios-ondraw-reporter-without-interop) is still a working starting point.antonis commentedon Nov 11, 2026
Closing this as an edge case for now. We can revisit this as we test and adopt future RN versions