Skip to content

iOS 26 crash: NSException from -[RNSTabBarController updateTabBarAppearance] on A18 Pro (production builds only) #3940

@nuvianlabs

Description

@nuvianlabs

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

  1. Expo SDK 54 app using expo-router with a (tabs) group (native bottom tabs via react-native-screens' RNSTabBarController).
  2. Build for TestFlight / App Store distribution (distribution: store).
  3. Install on iPhone 17 Pro running iOS 26.4.x.
  4. 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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    missing-infoThe user didn't precise the problem enoughmissing-reproThis issue need minimum repro scenarioplatform:iosIssue related to iOS part of the library

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions