You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On iOS 16+, enforceDesiredDeviceOrientation in RNSScreenWindowTraits.mm has two bugs that cause per-screen orientation changes to silently fail during navigation transitions:
Stale windowScene.interfaceOrientation — The heuristic checks interfaceOrientation to decide whether rotation is needed. This value can be stale after scene restoration, app relaunch, or a previous requestGeometryUpdate that changed internal metadata without visually rotating. When stale, the method thinks the device is already in the correct orientation and skips the rotation entirely. (Same root cause as Orientation is not locked as intended #2197)
Empty error handler on requestGeometryUpdate — When called during viewWillAppear, UIKit's internal orientation cache may still hold the outgoing screen's mask. requestGeometryUpdate validates against this stale cache and fails with:
Error Domain=UISceneErrorDomain Code=101
"None of the requested orientations are supported by the view controller.
Requested: portrait, portraitUpsideDown; Supported: landscapeRight"
The error handler is ^(NSError *_Nonnull error){} — the failure is silently swallowed.
These bugs make it unreliable to navigate between screens with different orientations (e.g. portrait home → landscape play screen → back to portrait). After 1-2 cycles the orientation gets permanently stuck.
Description
On iOS 16+,
enforceDesiredDeviceOrientationinRNSScreenWindowTraits.mmhas two bugs that cause per-screen orientation changes to silently fail during navigation transitions:Stale
windowScene.interfaceOrientation— The heuristic checksinterfaceOrientationto decide whether rotation is needed. This value can be stale after scene restoration, app relaunch, or a previousrequestGeometryUpdatethat changed internal metadata without visually rotating. When stale, the method thinks the device is already in the correct orientation and skips the rotation entirely. (Same root cause as Orientation is not locked as intended #2197)Empty error handler on
requestGeometryUpdate— When called duringviewWillAppear, UIKit's internal orientation cache may still hold the outgoing screen's mask.requestGeometryUpdatevalidates against this stale cache and fails with:The error handler is
^(NSError *_Nonnull error){}— the failure is silently swallowed.These bugs make it unreliable to navigate between screens with different orientations (e.g. portrait home → landscape play screen → back to portrait). After 1-2 cycles the orientation gets permanently stuck.
Related: expo/expo#43692, #2197, #1775
Steps to reproduce
git clone https://github.com/JeanDes-Code/orientation-lock-repronpm installpatches/react-native-screens+4.23.0.patch(the expo-screen-orientation patch can stay — it's equivalent to expo/expo#44181)npm installagain (to revert the react-native-screens patch)npx expo prebuild --clean && npx expo run:iosStack.Screen options={{ orientation: 'landscape_right' }}Snack or a link to a repository
https://github.com/JeanDes-Code/orientation-lock-repro
The repo includes a workaround patch for react-native-screens that:
setNeedsUpdateOfSupportedInterfaceOrientations+requestGeometryUpdateon iOS 16+ (bypasses the staleinterfaceOrientationheuristic)UIDevice setValue:@(orientation) forKey:@"orientation"in the error handlerScreens version
4.23.0
React Native version
0.83.4
Platforms
iOS
JavaScript runtime
Hermes
Workflow
Expo managed workflow
Architecture
Fabric (New Architecture)
Build type
Debug mode
Device
iOS simulator, Real device
Device model
iPhone 17 Pro Simulator (iOS 26.2), iPhone 15 Pro (iOS 18)
Acknowledgements
Yes