Description
RCTAppearance's setColorScheme: iterates every connected scene and asks each one for windows. The loop variable is declared UIWindowScene *, but that is a compile-time claim, not a runtime filter — connectedScenes returns UIScene objects of any concrete class.
A CarPlay app has a CPTemplateApplicationScene among its connected scenes. It is a UIScene, it is not a UIWindowScene, and it has no windows property. Sending it that message aborts the process.
RCTAppearance.mm#L112-L123, unchanged on main as of 2026-08-08:
- (void)setColorScheme:(NSString *)style
{
UIUserInterfaceStyle userInterfaceStyle = [RCTConvert UIUserInterfaceStyle:style];
NSMutableArray<UIWindow *> *windows = [NSMutableArray new];
for (UIWindowScene *scene in RCTSharedApplication().connectedScenes) {
[windows addObjectsFromArray:scene.windows]; // crashes on CPTemplateApplicationScene
}
for (UIWindow *window in windows) {
window.overrideUserInterfaceStyle = userInterfaceStyle;
}
}
On 0.86.0 the same body sits under RCT_EXPORT_METHOD(setColorScheme : (NSString *)style). Reproduced with the linked reproducer — a bare @react-native-community/cli init app on 0.86.0, no Expo and no third-party CarPlay library
Why this is easy to miss. The crash needs an app that has both a CarPlay scene and a call to Appearance.setColorScheme(). Ours is a delivery-driver app with a light/dark/system theme setting, so setColorScheme runs at every launch. The failure mode is misleading: the app dies on the phone, every time, but only while the phone is connected to CarPlay — and only this one app out of everything on the device. That reads like an application bug rather than a React Native one; it took a crash report to find.
This is distinct from the frequently reported RCTAppDelegate window-setup CarPlay problems (expo/expo#32702, #41777, birkir/react-native-carplay#184), which are about launching into CarPlay with no phone window. This one kills an app that is already running normally, the moment JS sets the color scheme.
Suggested fix — filter by class instead of trusting the loop variable's declared type:
for (UIScene *scene in RCTSharedApplication().connectedScenes) {
if (![scene isKindOfClass:[UIWindowScene class]]) {
continue;
}
[windows addObjectsFromArray:((UIWindowScene *)scene).windows];
}
We have run this as a patch-package patch in production since 2026-08-02; it fixes the crash with no other observable change. Other connectedScenes loops in the codebase may make the same assumption and are worth a look.
Steps to reproduce
Using the linked reproducer:
- npm install && (cd ios && pod install)
- Build and run on a simulator.
- In the Simulator, open I/O → External Displays → CarPlay.
- Open the app on the CarPlay screen — this is the step that matters, and it is easy to skip. The CPTemplateApplicationScene only connects once the app is opened on the car display.
- Now launch (or relaunch) the app on the phone screen.
Expected: the app launches and the color scheme is applied to the phone's windows. Actual: the process aborts immediately — -[CPTemplateApplicationScene windows]: unrecognized selector (see Stacktrace).
If step 4 is skipped the app launches fine, because no CarPlay scene is connected yet and the loop only sees window scenes. In a real car this ordering is invisible: the app is already on the car display, so every launch on the phone crashes — which is what made it look like an application bug rather than a React Native one.
This does not require Apple's CarPlay entitlement grant. The Simulator will run an app that simply declares the entitlement locally.
React Native Version
0.86.0
Affected Platforms
Runtime - iOS
Output of npx @react-native-community/cli info
System:
OS: macOS 26.5.2
CPU: (10) arm64 Apple M1 Pro
Memory: 392.13 MB / 32.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 22.17.0
path: ~/.nvm/versions/node/v22.17.0/bin/node
Yarn:
version: 1.22.22
path: ~/.nvm/versions/node/v22.17.0/bin/yarn
npm:
version: 11.6.2
path: ~/.nvm/versions/node/v22.17.0/bin/npm
Watchman:
version: 2025.06.23.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.16.2
path: /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 25.2
- iOS 26.2
- macOS 26.2
- tvOS 26.2
- visionOS 26.2
- watchOS 26.2
IDEs:
Xcode:
version: 26.2/17C52
path: /usr/bin/xcodebuild
Languages:
Ruby:
version: 3.4.4
path: /opt/homebrew/opt/ruby/bin/ruby
npmPackages:
"@react-native-community/cli":
installed: 20.1.0
wanted: 20.1.0
react:
installed: 19.2.3
wanted: 19.2.3
react-native:
installed: 0.86.0
wanted: 0.86.0
iOS:
hermesEnabled: true
newArchEnabled: true
Stacktrace or Logs
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[CPTemplateApplicationScene windows]: unrecognized selector sent to instance 0x10380caa0'
0 CoreFoundation __exceptionPreprocess + 160
1 libobjc.A.dylib objc_exception_throw + 72
2 CoreFoundation +[NSObject(NSObject) instanceMethodSignatureForSelector:] + 0
3 UIKitCore -[UIResponder doesNotRecognizeSelector:] + 232
4 CoreFoundation ___forwarding___ + 1216
5 CoreFoundation _CF_forwarding_prep_0 + 92
6 React -[RCTAppearance setColorScheme:] + 204
7 CoreFoundation __invoking___ + 144
8 CoreFoundation -[NSInvocation invoke] + 276
9 CoreFoundation -[NSInvocation invokeWithTarget:] + 60
10 React invocation function for block in facebook::react::ObjCTurboModule::performVoidMethodInvocation(facebook::jsi::Runtime&, char const*, NSInvocation*, NSMutableArray*) + 68
11 React std::__1::__function::__func<facebook::react::ObjCTurboModule::performVoidMethodInvocation(...)::$_0, ...>::operator()() + 104
12 libdispatch.dylib _dispatch_call_block_and_release + 24
13 libdispatch.dylib _dispatch_client_callout + 12
15 libdispatch.dylib _dispatch_main_queue_drain + 1184
16 libdispatch.dylib _dispatch_main_queue_callback_4CF + 40
17 CoreFoundation __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
18 CoreFoundation __CFRunLoopRun + 1920
19 CoreFoundation CFRunLoopRunSpecific + 536
20 GraphicsServices GSEventRunModal + 164
21 UIKitCore -[UIApplication _run] + 796
22 UIKitCore UIApplicationMain + 124
24 RNCarPlayAppearanceRepro specialized static UIApplicationDelegate.main() + 28
25 RNCarPlayAppearanceRepro static AppDelegate.$main() + 28
26 RNCarPlayAppearanceRepro main + 120
27 dyld_sim start_sim + 20
MANDATORY Reproducer
https://github.com/ipechy/RNCarPlayAppearanceRepro
Screenshots and Videos
No response
Description
RCTAppearance's setColorScheme: iterates every connected scene and asks each one for windows. The loop variable is declared UIWindowScene *, but that is a compile-time claim, not a runtime filter — connectedScenes returns UIScene objects of any concrete class.
A CarPlay app has a CPTemplateApplicationScene among its connected scenes. It is a UIScene, it is not a UIWindowScene, and it has no windows property. Sending it that message aborts the process.
RCTAppearance.mm#L112-L123, unchanged on main as of 2026-08-08:
On 0.86.0 the same body sits under RCT_EXPORT_METHOD(setColorScheme : (NSString *)style). Reproduced with the linked reproducer — a bare @react-native-community/cli init app on 0.86.0, no Expo and no third-party CarPlay library
Why this is easy to miss. The crash needs an app that has both a CarPlay scene and a call to Appearance.setColorScheme(). Ours is a delivery-driver app with a light/dark/system theme setting, so setColorScheme runs at every launch. The failure mode is misleading: the app dies on the phone, every time, but only while the phone is connected to CarPlay — and only this one app out of everything on the device. That reads like an application bug rather than a React Native one; it took a crash report to find.
This is distinct from the frequently reported RCTAppDelegate window-setup CarPlay problems (expo/expo#32702, #41777, birkir/react-native-carplay#184), which are about launching into CarPlay with no phone window. This one kills an app that is already running normally, the moment JS sets the color scheme.
Suggested fix — filter by class instead of trusting the loop variable's declared type:
We have run this as a patch-package patch in production since 2026-08-02; it fixes the crash with no other observable change. Other connectedScenes loops in the codebase may make the same assumption and are worth a look.
Steps to reproduce
Using the linked reproducer:
Expected: the app launches and the color scheme is applied to the phone's windows. Actual: the process aborts immediately — -[CPTemplateApplicationScene windows]: unrecognized selector (see Stacktrace).
If step 4 is skipped the app launches fine, because no CarPlay scene is connected yet and the loop only sees window scenes. In a real car this ordering is invisible: the app is already on the car display, so every launch on the phone crashes — which is what made it look like an application bug rather than a React Native one.
This does not require Apple's CarPlay entitlement grant. The Simulator will run an app that simply declares the entitlement locally.
React Native Version
0.86.0
Affected Platforms
Runtime - iOS
Output of
npx @react-native-community/cli infoStacktrace or Logs
MANDATORY Reproducer
https://github.com/ipechy/RNCarPlayAppearanceRepro
Screenshots and Videos
No response