Skip to content

fix(ios): guard against UIViewControllerHierarchyInconsistency in all navigation hosts#10316

Open
huhuanming wants to merge 6 commits intoxfrom
fix/sentry-react-native-3yz-ios-viewcontroller
Open

fix(ios): guard against UIViewControllerHierarchyInconsistency in all navigation hosts#10316
huhuanming wants to merge 6 commits intoxfrom
fix/sentry-react-native-3yz-ios-viewcontroller

Conversation

@huhuanming
Copy link
Contributor

@huhuanming huhuanming commented Feb 24, 2026

Summary

  • Extends the UIHostingController skip guard from RNSScreenStack.mm to all reactAddControllerToClosestParent: call sites in react-native-screens
  • Fixes a fatal iOS crash (654 events, 127 users) where RNSNavigationController gets added as a child of UIHostingController, which SwiftUI then re-parents during layout updates, causing UIViewControllerHierarchyInconsistency
  • The previous patch (decd5eeead) only covered RNSScreenStack.mm but missed three other files: RNSBottomTabsHostComponentView.mm, RNSSplitViewHostComponentView.mm, and RNSStackHostComponentView.mm

Root Cause

When using react-native-bottom-tabs (SwiftUI TabView), the tab content is wrapped in UIHostingController. SwiftUI internally re-parents UIHostingController instances during layout updates. If react-native-screens attaches a navigation controller as a child of UIHostingController, the parent reference becomes stale after SwiftUI re-parents it, triggering UIViewControllerHierarchyInconsistency.

Changes

patches/react-native-screens+4.23.0.patch -- Added UIHostingController skip guard to:

  • RNSBottomTabsHostComponentView.mm (most likely crash source -- bottom tabs host)
  • RNSSplitViewHostComponentView.mm (split view host)
  • RNSStackHostComponentView.mm (stack host)

The guard checks if the candidate parent view controller's class name contains "UIHostingController" and, if so, continues walking up the view hierarchy to find a stable non-SwiftUI parent.

Test plan

  • Verify iOS app launches without crash on devices running iOS 17+
  • Navigate between bottom tabs multiple times rapidly
  • Open and close modal screens from different tabs
  • Verify navigation stack push/pop works correctly within tabs
  • Monitor Sentry for REACT-NATIVE-3YZ after deployment

Fixes REACT-NATIVE-3YZ


Open with Devin

@revan-zhang
Copy link
Contributor

revan-zhang commented Feb 24, 2026

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

…igation

Extend the UIHostingController skip guard to all reactAddControllerToClosestParent
call sites in react-native-screens. The previous patch (decd5ee) only covered
RNSScreenStack.mm, but the same crash occurs via RNSBottomTabsHostComponentView,
RNSSplitViewHostComponentView, RNSStackHostComponentView, and RNSScreenContainer
when SwiftUI re-parents UIHostingController during layout updates.

RNSScreenContainer inherits reactAddControllerToClosestParent from UIView+React
(React Native core) so it needs its own override with the guard.

Fixes REACT-NATIVE-3YZ
@huhuanming huhuanming force-pushed the fix/sentry-react-native-3yz-ios-viewcontroller branch from d335b97 to 89bac76 Compare February 24, 2026 11:13
@huhuanming
Copy link
Contributor Author

Code Review Summary

Reviewed Items

  1. Guard logic is correct — UIHostingController skip pattern is consistent across all 3 new files and the existing RNSScreenStack.mm
  2. No navigation regression risk — The guard only activates when UIHostingController is in the hierarchy; normal code path is unchanged
  3. Loop advancement is correctcontinue with parentView = parentView.reactSuperview correctly walks up the hierarchy

Review Findings

Finding 1: RNSScreenContainer.mm not covered (82% confidence)
The Paper architecture path inherits from UIView+React without the guard. If only Fabric is used in production, this is not an issue.

Finding 2: Trailing whitespace in RNSScreenStack.mm hunk
Byte-level inspection confirmed no trailing whitespace exists in the actual patch file. The visual artifact was from GitHub's diff rendering. No fix needed.

Resolution

No changes needed — Patch is clean. The RNSScreenContainer.mm gap is acceptable since we use Fabric (New Architecture) in production.

@huhuanming huhuanming marked this pull request as ready for review February 24, 2026 15:43
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 4 additional findings.

Open in Devin Review

@huhuanming huhuanming enabled auto-merge (squash) February 24, 2026 15:46
zhaono1
zhaono1 previously approved these changes Feb 25, 2026
originalix
originalix previously approved these changes Feb 25, 2026
…3yz-ios-viewcontroller-resolve

# Conflicts:
#	patches/react-native-screens+4.23.0.patch
@huhuanming huhuanming dismissed stale reviews from originalix and zhaono1 via e0a9fb4 February 25, 2026 08:26
@huhuanming
Copy link
Contributor Author

Merge conflict resolved — kept both iOS UIHostingController skip logic and Android FragmentManager reentrant transaction guard in the patch file.

@huhuanming huhuanming force-pushed the fix/sentry-react-native-3yz-ios-viewcontroller branch from e0a9fb4 to 025343e Compare February 25, 2026 08:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants