Environment
- react-native-screens: 4.23.0 (also reproduces on 4.22, 4.16 — we've tried many; crash appears unrelated to version)
- react-native: 0.81.5
- Expo SDK: 54 (
expo-router 6.0.23)
- new arch: tested BOTH
true and false — crash occurs on both
- iOS: 26.4.1 (build 23E254) and 26.4.2
- Device: iPhone 17 Pro (iPhone18,2) — A18 Pro chip
- Distribution: TestFlight store builds (works fine in dev-client connected to Metro)
Summary
Production/TestFlight builds crash with EXC_CRASH (SIGABRT) triggered by an uncaught ObjC NSException propagating out of -[RNSTabBarController updateTabBarAppearance] at RNSTabBarController.mm:182. The exception is surfaced through the React Native TurboModule bridge's ObjCTurboModule::performVoidMethodInvocation on a background dispatch queue, so the runtime abort()s the process.
Dev-client builds running against Metro do NOT crash on launch; they run for ~60 seconds and then crash with a related SwiftUI HostingScrollView / UIFocusSystem / __UIViewWillBeRemovedFromSuperview stack. Appears to be the same underlying bug expressed through two different surface symptoms depending on build configuration.
Reproduction
- Expo SDK 54 app using
expo-router with a (tabs) group (native bottom tabs via react-native-screens' RNSTabBarController).
- Build for TestFlight / App Store distribution (
distribution: store).
- Install on iPhone 17 Pro running iOS 26.4.x.
- Launch → app crashes within 0.15s of launch (SIGABRT).
The crash does NOT reproduce:
- On simulators (only on physical A18 Pro device).
- When running a dev-client build connected to Metro.
- When
enableScreens(false) is called at app init (our workaround — bypasses RNSTabBarController entirely).
Workaround we're applying
Adding to the root _layout.tsx:
import { enableScreens } from 'react-native-screens';
enableScreens(false);
This loses native-screen optimizations but keeps the app launchable.
Symbolicated crash stack (Thread 4, crashing)
0 libsystem_kernel.dylib __pthread_kill + 8
1 libsystem_pthread.dylib pthread_kill + 268
2 libsystem_c.dylib abort + 148
3 libc++abi.dylib __abort_message + 132
4 libc++abi.dylib demangling_terminate_handler() + 272
5 libobjc.A.dylib _objc_terminate() + 172
6 libc++abi.dylib std::__terminate(void (*)()) + 16
7 libc++abi.dylib __cxa_rethrow + 188
8 libobjc.A.dylib objc_exception_rethrow + 44
9 React invocation function for block in facebook::react::
ObjCTurboModule::performVoidMethodInvocation(
facebook::jsi::Runtime&, char const*,
NSInvocation*, NSMutableArray*) + 192
(RCTTurboModule.mm:441)
10 React facebook::react::ObjCTurboModule::
performVoidMethodInvocation(...)::$_1::operator()() + 64
(RCTTurboModule.mm:460)
11-14 React (std::function boilerplate)
15 libdispatch.dylib _dispatch_call_block_and_release + 32
16 libdispatch.dylib _dispatch_client_callout + 16
17 libdispatch.dylib _dispatch_lane_serial_drain + 740
18 libdispatch.dylib _dispatch_lane_invoke + 392
19 libdispatch.dylib _dispatch_root_queue_drain_deferred_wlh + 284
20 libdispatch.dylib _dispatch_workloop_worker_thread + 720
21 libsystem_pthread.dylib _pthread_wqthread + 292
22 libsystem_pthread.dylib start_wqthread + 8
Additional symbolicated frames (from our own symbolication of stripped production binary against a local dSYM build of the same source):
-[RNSTabBarController updateTabBarAppearance] (RNSTabBarController.mm:182)
-[RCTModuleData gatherConstantsAndSignalJSRequireEnding:] (RCTModuleData.mm:440)
__41-[RCTModuleMethod processMethodSignature]_block_invoke_4/_11/_15 (RCTModuleMethod.mm:0/306/314)
invocation function for block in RCTCurrentAppState() (RCTAppState.mm:24)
-[RCTDeviceInfo _cleanupObservers] (RCTDeviceInfo.mm:137)
RNSTabBarController.mm:182 is the multi-line message send inside -[RNSTabBarController updateTabBarAppearance] that invokes [_tabBarAppearanceCoordinator updateAppearanceOfTabBar:...]. That's where the NSException is originating — the coordinator's subsequent calls to UIKit's tab-bar/focus APIs on iOS 26 throw.
Things we verified
- Same stack on builds from two weeks ago (April 10) through current (April 24) — this has been happening for some time but was only recently diagnosable once we got Apple-side symbolication via Xcode Organizer.
- Apple's crash grouping in Organizer misattributes this to
hermes::vm::HadesGC::Executor::worker() (Thread 10 — the idle Hermes GC worker thread) instead of the actual crashing Thread 4. Worth knowing for anyone seeing a similar analyticsPointName in their ASC dashboard — the real crash is elsewhere.
- The entire source diff between rn-screens 4.23 → 4.24 → 4.25-nightly for the tabs-related files is CLASS RENAMES ONLY (
RNSBottomTabs* → RNSTabs*). Zero semantic changes to tab-bar-appearance or focus handling. No apparent fix in main yet.
Ask
Any insight into what tab-bar or focus-system API on iOS 26 / iPhone18,2 is throwing the NSException from within updateAppearanceOfTabBar:withHostComponentView:tabScreenControllers:imageLoader:? We have enough reproducer access to apply and test a patch.
Happy to provide the full symbolicated .crash files on request (contain bundle IDs and TestFlight metadata so not pasted inline).
Environment
expo-router6.0.23)trueandfalse— crash occurs on bothSummary
Production/TestFlight builds crash with
EXC_CRASH (SIGABRT)triggered by an uncaught ObjCNSExceptionpropagating out of-[RNSTabBarController updateTabBarAppearance]atRNSTabBarController.mm:182. The exception is surfaced through the React Native TurboModule bridge'sObjCTurboModule::performVoidMethodInvocationon a background dispatch queue, so the runtimeabort()s the process.Dev-client builds running against Metro do NOT crash on launch; they run for ~60 seconds and then crash with a related SwiftUI
HostingScrollView/UIFocusSystem/__UIViewWillBeRemovedFromSuperviewstack. Appears to be the same underlying bug expressed through two different surface symptoms depending on build configuration.Reproduction
expo-routerwith a(tabs)group (native bottom tabs viareact-native-screens'RNSTabBarController).distribution: store).The crash does NOT reproduce:
enableScreens(false)is called at app init (our workaround — bypassesRNSTabBarControllerentirely).Workaround we're applying
Adding to the root
_layout.tsx:This loses native-screen optimizations but keeps the app launchable.
Symbolicated crash stack (Thread 4, crashing)
Additional symbolicated frames (from our own symbolication of stripped production binary against a local dSYM build of the same source):
RNSTabBarController.mm:182is the multi-line message send inside-[RNSTabBarController updateTabBarAppearance]that invokes[_tabBarAppearanceCoordinator updateAppearanceOfTabBar:...]. That's where theNSExceptionis originating — the coordinator's subsequent calls to UIKit's tab-bar/focus APIs on iOS 26 throw.Things we verified
hermes::vm::HadesGC::Executor::worker()(Thread 10 — the idle Hermes GC worker thread) instead of the actual crashing Thread 4. Worth knowing for anyone seeing a similaranalyticsPointNamein their ASC dashboard — the real crash is elsewhere.RNSBottomTabs*→RNSTabs*). Zero semantic changes to tab-bar-appearance or focus handling. No apparent fix in main yet.Ask
Any insight into what tab-bar or focus-system API on iOS 26 / iPhone18,2 is throwing the NSException from within
updateAppearanceOfTabBar:withHostComponentView:tabScreenControllers:imageLoader:? We have enough reproducer access to apply and test a patch.Happy to provide the full symbolicated
.crashfiles on request (contain bundle IDs and TestFlight metadata so not pasted inline).