From 3587335140428861b1699da54557ddb0d3dc4a5c Mon Sep 17 00:00:00 2001 From: Diagnostics Bot Date: Wed, 8 Apr 2026 10:16:40 -0700 Subject: [PATCH] Handle missing viewState gracefully in SurfaceMountingManager.addViewAt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: ## Problem `SurfaceMountingManager.addViewAt()` throws `RetryableMountingLayerException` when a view tag is not found in the `tagToViewState` map. This exception is **not handled** in the `IntBufferBatchMountItem` execution path — the retry logic in `MountItemDispatcher` only catches this for `DispatchCommandMountItem`. The exception propagates and crashes the app. **Crash**: `RetryableMountingLayerException: Unable to find viewState for tag X. Surface stopped: false` **Process**: `com.oculus.firsttimenux:login` **Impact**: 44,763 occurrences / 14,674 affected users in 30 days Logview link: [252c85116a7ab5c4ec93ef3c3373cf9d](https://www.internalfb.com/logview/system_vros_crashes/252c85116a7ab5c4ec93ef3c3373cf9d) ## Root Cause `addViewAt()` uses `getViewState()` which throws on missing tags, while other methods like `removeViewAt()`, `updateProps()`, `updateLayout()`, and `deleteView()` all use `getNullableViewState()` with graceful null handling (soft exception log + early return). This inconsistency means `addViewAt` is the only mount operation that crashes when encountering a timing-related missing view state. ## Fix Changed `addViewAt()` to use `getNullableViewState()` for both parent and child tag lookups, matching the established pattern used by `removeViewAt`, `updateProps`, `updateLayout`, and `deleteView`. On null, a soft exception is logged with the `SURFACE_MOUNTING_MANAGER_MISSING_VIEWSTATE` category and the operation returns early. Reviewed By: cortinico Differential Revision: D99760257 --- .../fabric/mounting/SurfaceMountingManager.kt | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.kt index 485dd80d02f1..c09962b407cd 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.kt @@ -282,7 +282,14 @@ internal constructor( return } - val parentViewState = getViewState(parentTag) + val parentViewState = getNullableViewState(parentTag) + if (parentViewState == null) { + ReactSoftExceptionLogger.logSoftException( + ReactSoftExceptionLogger.Categories.SURFACE_MOUNTING_MANAGER_MISSING_VIEWSTATE, + ReactNoCrashSoftException("Unable to find viewState for tag: [$parentTag] for addViewAt"), + ) + return + } if (parentViewState.view !is ViewGroup) { val message = "Unable to add a view into a view that is not a ViewGroup. ParentTag: $parentTag - Tag: $tag - Index: $index" @@ -290,7 +297,14 @@ internal constructor( throw IllegalStateException(message) } val parentView = parentViewState.view as ViewGroup - val viewState = getViewState(tag) + val viewState = getNullableViewState(tag) + if (viewState == null) { + ReactSoftExceptionLogger.logSoftException( + ReactSoftExceptionLogger.Categories.SURFACE_MOUNTING_MANAGER_MISSING_VIEWSTATE, + ReactNoCrashSoftException("Unable to find viewState for tag: [$tag] for addViewAt"), + ) + return + } val view = viewState.view checkNotNull(view) { "Unable to find view for viewState $viewState and tag $tag" }