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
{{ message }}
Repository navigation
[$250] [Sentry: APP-N5H] HybridApp Android: native tab bar crashes with more than 6 items #104505
Last seen: 2026-10-20 (ongoing, Sentry marks it as escalating)
Platform: Android HybridApp
App version(s): 9.5.13-0 (31 users) and 9.5.13-1 (4 users), plus 1 user each on 9.5.9-4, 9.5.10-0, 9.5.11-0, 9.5.13-3 and 9.5.14-0
Affected route(s) (parameterized): native screen; the sample event was on Settings_Troubleshoot
Mechanism: UncaughtExceptionHandler, level fatal
Most users were on 9.5.13-0, a staging build. 9.5.13-6 is now rolling out to production on Android, so this may grow.
Stack trace (top frames, first-party only)
com.swmansion.rnscreens.ScreenStack.onUpdate (ScreenStack.kt:323)
com.swmansion.rnscreens.gamma.tabs.container.TabsContainer.onAttachedToWindow (TabsContainer.kt:311)
com.swmansion.rnscreens.gamma.tabs.container.TabsContainer.flushPendingUpdates (TabsContainer.kt:212)
com.swmansion.rnscreens.gamma.tabs.container.TabsContainer.updateNavigationMenuStructure (TabsContainer.kt:545)
com.swmansion.rnscreens.gamma.tabs.container.MenuHelpersKt.getOrCreateMenuItemForFragment (MenuHelpers.kt:8)
androidx.appcompat.view.menu.MenuBuilder.add
IllegalArgumentException: Maximum number of items supported by CustomBottomNavigationView is 6
Suspected cause
The native tab container adds a seventh item to the Android bottom navigation menu, which supports at most 6. It happens when a screen stack attaches the tab container again, so the tab menu items may be added again instead of reused.
Reproduction
Unknown. See the Sentry events linked from the Sentry issue.
changed the title [-][Sentry: APP-N5H] HybridApp Android: native tab bar crashes with more than 6 items[/-][+][$175] [Sentry: APP-N5H] HybridApp Android: native tab bar crashes with more than 6 items[/+]on Oct 20, 2026
Please re-state the problem that we are trying to solve in this issue.
HybridApp on Android crashes with IllegalArgumentException: Maximum number of items supported by CustomBottomNavigationView is 6 when a screen stack re-attaches the native tab container or when more than 6 navigation items are added.
What is the root cause of that problem?
Android's BottomNavigationView / CustomBottomNavigationView enforces a hard limit of maximum 6 items (MAX_ITEM_COUNT = 6).
In PR #101339 and patch @react-navigation+bottom-tabs+7.19.2+003+hidden-tab-items.patch, the app registers 6 tab routes:
HOME, REPORTS_SPLIT_NAVIGATOR, SEARCH_FULLSCREEN_NAVIGATOR, INSIGHTS, WORKSPACE_NAVIGATOR, SETTINGS_SPLIT_NAVIGATOR.
Although getTabWithoutBarItem designates one route as abBarItemHidden: true to stay at 5 items, when a screen stack re-attaches (ScreenStack.kt:onUpdate -> TabsContainer.kt:onAttachedToWindow -> flushPendingUpdates -> updateNavigationMenuStructure), menu items from the previous fragment attachment can persist or re-accumulate without clearing or recycling if lushPendingUpdates runs repeatedly during stack transitions. Adding the new items pushes the menu size to 7 (or above), throwing IllegalArgumentException: Maximum number of items supported by CustomBottomNavigationView is 6.
What changes do you think we should make in order to solve the problem?
In TabsContainer.kt (or via patch to
eact-native-screens), before calling updateNavigationMenuStructure / getOrCreateMenuItemForFragment, ensure menu.clear() is called or check that existing menu items matching the fragment tabs are reused/updated rather than re-added.
In @react-navigation+bottom-tabs+7.19.2+003+hidden-tab-items.patch, strictly guard that routes marked with abBarItemHidden: true are never passed as native tab fragments to RNScreens under any transition state.
Automated Tests
Add a test in ScreenStackTest / navigation tests that mounts the native tab navigator, performs stack pushes and pops (such as opening Settings_Troubleshoot), and verifies that the menu items count in BottomNavigationView never exceeds 5.
Please re-state the problem that we are trying to solve in this issue.
On Android HybridApp, navigating between screens (e.g., visiting Settings_Troubleshoot or during screen transitions inside a ScreenStack) crashes fatally with: IllegalArgumentException: Maximum number of items supported by CustomBottomNavigationView is 6
thrown from:
In react-native-screens (gamma tabs on Android), TabsContainer manages bottom navigation tabs using CustomBottomNavigationView (based on Android Material's BottomNavigationView). Android's bottom navigation menu enforces a strict hardware constraint: MAX_ITEM_COUNT = 6 (or 5 standard, 6 custom). Adding a 7th item to MenuBuilder throws IllegalArgumentException.
In ScreenStack.kt:286, when screen fragments are updated or re-appended in stack order, the fragment containing the tab bar is detached and re-attached to the window (transaction.remove(wrapper.fragment) followed by transaction.add(...)).
When TabsContainer.onAttachedToWindow() executes, it calls flushPendingUpdates() -> updateNavigationMenuStructure().
In updateNavigationMenuStructure(), TabsContainer iterates through its tab fragments and calls getOrCreateMenuItemForFragment(fragment) which delegates to bottomNavigationView.menu.add(...).
However, updateNavigationMenuStructure() does not clear or synchronize the existing bottomNavigationView.menu prior to re-populating items. Because items from the initial layout pass are already present in the menu, re-adding the tabs appends duplicate menu items to the MenuBuilder. As soon as menu.size() reaches 7 (e.g. 4 tabs added twice = 8 items), Android throws IllegalArgumentException: Maximum number of items supported by CustomBottomNavigationView is 6.
What alternative solutions did you explore? (Optional)
None, clearing or diffing existing menu items in TabsContainer.updateNavigationMenuStructure before adding items is the cleanest, idiomatic solution.
What changes do you think we should make in order to solve the problem?
Add a patch in patches/react-native-screens/ (or update existing gamma patches, e.g. react-native-screens+4.28.0+006+clear-tab-menu-before-update.patch):
In node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsContainer.kt:
Before populating fragments in updateNavigationMenuStructure(), clear the existing menu:
--- a/node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsContainer.kt+++ b/node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsContainer.kt@@ -540,6 +540,7 @@ class TabsContainer(
}
private fun updateNavigationMenuStructure() {
+ bottomNavigationView.menu.clear()
fragments.forEachIndexed { index, fragment ->
val menuItem = getOrCreateMenuItemForFragment(fragment)
// configure item...
Or in MenuHelpers.kt:
Ensure that getOrCreateMenuItemForFragment checks bottomNavigationView.menu.findItem(fragment.id) instead of unconditionally calling menu.add(...).
What automated tests can you add to prevent this from re-occurring?
Add an Android instrumented/unit test for TabsContainer verifying that calling onAttachedToWindow() and flushPendingUpdates() repeatedly on a TabsContainer with 4-5 tabs never causes bottomNavigationView.menu.size() to exceed the fragment count or throw IllegalArgumentException.
There are two interconnected defects in react-native-screens gamma tabs on Android:
Child Removal Failure in Fabric (TabsHostViewManager):
In React Native Fabric, ViewGroupManager manages view additions and removals by inspecting child views via getChildCount(parent) and getChildAt(parent, index).
In TabsHostViewManager.kt, TabsHost does not attach TabsScreen views directly as Android ViewGroup children (they are managed in an internal renderedScreens list and encapsulated in TabsScreenFragment inside TabsContainer.tabsModel).
However, TabsHostViewManager does not override getChildCount or getChildAt. Consequently, React Native defaults to parent.childCount (which only sees the root container, count = 1).
When Fabric attempts to remove an inactive or toggled tab child at index > 0, getChildAt(parent, index) returns out of bounds or mismatches, causing Fabric to consider the view "already removed from parent" and skip calling removeViewAt / removeView.
As a result, TabsHost.unmountReactSubviewAt and TabsContainer.removeTabsScreenAt are never called for the old tab. When the tab or replacement screen is re-mounted, TabsHostViewManager.addView calls mountReactSubviewAt -> container.addTabsScreenAt, appending another fragment into tabsModel.
Every tab transition or beta re-render leaks stale fragments into tabsModel, causing tabsModel.size to grow beyond 5 to 7 or more.
Uncapped Menu Population against Hardware Limits in updateNavigationMenuStructure():
In TabsContainer.kt:532-547:
privatefunupdateNavigationMenuStructure() {
val menu = bottomNavigationView.menu
val isMenuInSync =
menu.size == tabsModel.size &&
tabsModel.withIndex().all { (index, fragment) ->
menu.getItem(index).itemId == fragment.menuItemId
}
if (isMenuInSync) return
menu.clear()
tabsModel.forEach { fragment ->
menu.getOrCreateMenuItemForFragment(fragment)
}
}
Notice that menu.clear() on line 543 does clear bottomNavigationView.menu. However, tabsModel.forEach iterates over all items in tabsModel without checking bottomNavigationView.maxItemCount (MAX_ITEM_COUNT = 6 in CustomBottomNavigationView / Android Material NavigationBarMenu).
In TabsHost.kt:76, mountReactSubviewAt only checks index < bottomNavigationViewMaxItemCount, never checking whether renderedScreens.size >= bottomNavigationViewMaxItemCount or whether the TabsScreen is already mounted.
When ScreenStack.onUpdate executes (e.g. re-attaching screens in stack order via transaction.commitNowAllowingStateLoss()), TabsContainer.onAttachedToWindow calls flushPendingUpdates() -> updateNavigationMenuStructure(). Because tabsModel accumulated 7 or more fragments, tabsModel.forEach attempts to add the 7th item into bottomNavigationView.menu.
NavigationBarMenu.addInternal detects size() + 1 > maxItemCount (7 > 6) and throws IllegalArgumentException: Maximum number of items supported by CustomBottomNavigationView is 6.
What alternative solutions did you explore? (Optional)
Attempting to only cap at the JS layer (NativeBottomTabView.native.js) is insufficient because Fabric view re-ordering and remount cycles on Android will still leak native fragments inside TabsHost.renderedScreens and TabsContainer.tabsModel if TabsHostViewManager cannot report its children. Both the view manager lifecycle and native container menu bounds must be secured.
What changes do you think we should make in order to solve the problem?
Add a patch in patches/react-native-screens/react-native-screens+4.28.0+006+fix-tabs-host-child-lifecycle-and-menu-limit.patch:
In TabsHostViewManager.kt:
Override getChildCount and getChildAt to reflect renderedScreens so Fabric can successfully unmount child screens:
In updateNavigationMenuStructure(), bound the iteration strictly to bottomNavigationView.maxItemCount:
privatefunupdateNavigationMenuStructure() {
val menu = bottomNavigationView.menu
val isMenuInSync =
menu.size == tabsModel.size &&
tabsModel.withIndex().all { (index, fragment) ->
menu.getItem(index).itemId == fragment.menuItemId
}
if (isMenuInSync) {
return
}
menu.clear()
val maxItems = bottomNavigationView.maxItemCount
tabsModel.take(maxItems).forEach { fragment ->
menu.getOrCreateMenuItemForFragment(fragment)
}
}
What automated tests can you add to prevent this from re-occurring?
In Android unit/integration tests (TabsContainerTest / TabsHostTest), verify that repeatedly mounting, unmounting, and re-mounting tabs on TabsHost with Fabric view manager dispatches:
Maintains renderedScreens.size == tabsModel.size.
Never exceeds bottomNavigationView.maxItemCount.
Never throws IllegalArgumentException during onAttachedToWindow() and flushPendingUpdates().
In tests/unit/NativeBottomTabViewTest.tsx, add test cases simulating rapid navigation transitions across tab routes and beta toggles to ensure the number of native Tabs.Screen children mounted to Tabs.Host never exceeds 5.
Please re-state the problem that we are trying to solve in this issue.
On Android HybridApp, the app crashes fatally with IllegalArgumentException: Maximum number of items supported by CustomBottomNavigationView is 6, thrown while the native tab container rebuilds its bottom navigation menu after being re-attached by a screen stack (Sentry APP-N5H).
What is the root cause of that problem?
The native tab bar is react-native-screens' TabsHost. Tab screens are not regular view children of TabsHost: mountReactSubviewAt stores each TabsScreen in an internal renderedScreens list and hands it to TabsContainer, which wraps it in a fragment and renders it inside the container's own content view:
When React removes a tab screen, Fabric's SurfaceMountingManager.removeViewAt first verifies the removal: it asks the parent's view manager for the child at that index via getChildAt, and when the tag does not match, it scans the parent's raw view children for the tag. If the tag is not found there either, it logs "view already removed from parent!" and returns without ever calling the view manager's removeViewAt:
TabsHostViewManager does not override getChildCount/getChildAt, so the default implementation reads the raw FrameLayout children of TabsHost — and those contain only the internal TabsContainer, never the TabsScreen views:
The result is that on Android, every native removal of a tab screen is silently skipped: unmountReactSubviewAt never runs, and the removed screen stays in renderedScreens and in TabsContainer's tabsModel forever. The app registers exactly six tabs — the maximum the Material bottom navigation view supports. Whenever React recreates the tab screens while the TabsHost view itself survives (a navigation state reset regenerates the route keys, so all six screens are torn down and recreated; the sample Sentry event sits on the Troubleshoot screen, whose "Reset and refresh" option wipes and reloads local app state while preserving the session), the six stale entries remain and the replacements are appended. The size guard in mountReactSubviewAt only checks the insertion index (always 0–5), not the total size, so tabsModel silently grows past the cap.
The crash then surfaces later, on re-attach: flushPendingUpdates is a no-op while the container is detached (for example while a pushed stack screen covers it), so the first menu rebuild runs from onAttachedToWindow — which is why the stack goes through ScreenStack.onUpdate. updateNavigationMenuStructure clears the menu and re-adds one item per tabsModel entry, and the seventh add throws:
The defect is still present on the latest react-native-screens nightly (the tabs code moved out of the gamma namespace, but TabsHostViewManager still has no getChildCount/getChildAt overrides and the menu rebuild is unchanged), so a library bump does not fix this.
What changes do you think we should make in order to solve the problem?
Add a new sequenced patch to patches/react-native-screens/ (with the matching details.md entry) that lets Fabric see the tab screens as children of TabsHost, the same way react-native-screens already handles its other fragment-based parents — ScreenStackViewManager and ScreenContainerViewManager both override getChildCount and getChildAt to answer from their internal screen lists instead of the raw view children:
Concretely: expose the rendered tab screens from TabsHost through two small internal accessors (the count of renderedScreens and the screen at a given index), and override getChildCount and getChildAt in TabsHostViewManager to delegate to them. With that in place, Fabric's verification in removeViewAt finds the expected tag at the expected index and proceeds to call the view manager's removeViewAt, so unmountReactSubviewAt runs, the removed screen leaves renderedScreens and tabsModel, and any later menu rebuild works with exactly the live tabs. The over-cap menu.add can no longer happen, and stale fragments no longer accumulate across remounts.
Since the missing overrides are still present upstream, this should also be reported to software-mansion/react-native-screens, and the patch can be dropped once an upstream release ships the fix.
What alternative solutions did you explore? (Optional)
Making updateNavigationMenuStructure defensive — capping the rebuild at the menu's maximum or deduplicating tabsModel by screen key — hides the crash but keeps the real defect: the stale TabsScreenFragment entries stay registered, keep participating in selection lookups, and the bar could show items for screens React has already dropped. Similarly, tightening the guard in mountReactSubviewAt to check the total size rather than the insertion index would only turn this crash into a different, earlier one. Fixing the child bookkeeping so removals actually reach the view manager addresses the cause rather than the symptom.
The bar never gets 7 items from a double add. updateNavigationMenuStructure already does menu.clear() and then adds one item per entry in tabsModel (TabsContainer.kt#L532-L547). So the crash means tabsModel really holds 7 TabsScreens. Native tabs get added but are never removed.
The reason is that Android can't remove a native tab. TabsHostViewManager overrides removeViewAt but not getChildAt/getChildCount (TabsHostViewManager.kt#L50-L55). Before removing anything, Fabric checks which child is at that index through viewGroupManager.getChildAt (SurfaceMountingManager.kt#L456-L482). The default returns the real Android child of TabsHost, which is the container and not a TabsScreen. The tag doesn't match, so Fabric logs view already removed from parent! and returns. TabsHost.unmountReactSubviewAt is never called, but inserts still go through mountReactSubviewAt (TabsHost.kt#L85-L105). The gamma stack sibling already has these overrides (StackHostViewManager.kt#L52-L57), but the tabs one doesn't.
In the App, a tab gets removed and inserted whenever the Insights beta flips. We register 6 tabs, and one of them is marked tabBarItemHidden: Account with the beta, Insights without it (getTabWithoutBarItem.ts#L8-L10, TabNavigator.native.tsx#L41-L48). The hidden-tab patch renders null instead of a Tabs.Screen for the hidden route (hidden-tab-items.patch#L68-L70). Each flip inserts one native tab and leaves the stale one behind:
start: 5 tabs
1st flip: Insights inserted, Account removal skipped, so 6 (no crash yet, the bar shows a stale extra tab)
2nd flip: Account inserted again as a new view, Insights removal skipped, so 7, and MenuBuilder.add throws
That's why the sample event is on Settings_Troubleshoot. There are two ways to flip the beta twice from there:
Troubleshoot > Beta overrides, toggle insightsPage twice (DynamicBetaOverridesPage.tsx#L54-L61). This page is only on staging/internal builds, which is why most of the users are on the 9.5.13-0 staging build.
Troubleshoot > Clear cache and restart. BETAS isn't in KEYS_TO_PRESERVE (App.ts#L132-L159), so for an Insights user it goes from on to unknown (off) and back to on after OpenApp.
The tab container is detached while the RHP covers it, so flushPendingUpdates doesn't run until the stack attaches the container again. That's the ScreenStack.onUpdate -> TabsContainer.onAttachedToWindow -> flushPendingUpdates path in the trace (TabsContainer.kt#L291-L311).
This is the same native bug as #104230. #104238 worked around it only for the route key change, by keying native tabs by route name (patch 004). That patch landed in 9.5.13-1, which is why 9.5.13-0 has most of the events. A hidden/visible swap still adds and removes a real Tabs.Screen, so 9.5.13-1, 9.5.13-3 and 9.5.14-0 still crash.
What changes do you think we should make in order to solve the problem?
Fix the removal itself so Fabric reaches unmountReactSubviewAt. Add a new patch, react-native-screens+4.28.0+006+fix-android-tabs-host-child-removal.patch, that gives TabsHostViewManager the same overrides StackHostViewManager has.
Now Fabric finds the matching tag at that index and calls removeViewAt -> unmountReactSubviewAt, so tabsModel stays in sync with what JS renders. The beta flip ends with 5 items, the stale extra tab is gone, and the menu can't reach 7. Nothing changes on iOS, and we don't need to touch the JS hidden-tab logic. I'd keep patch 004 because it still prevents the remount flash, but its "Remove this patch once react-native-screens removes Android tabs correctly" note in details.md would then be satisfied for the Android part. I'd also report it upstream, since StackHost already has the fix.
For tests, the bug is native, so a jest test can't reach it. I'll cover it with a manual QA step on Android: toggle insightsPage in Beta overrides 3 times and go back, then do Clear cache and restart as an Insights user, and check that the bar always shows exactly 5 tabs without crashing. I'll also add a jest test for the JS contract we rely on: flipping CONST.BETAS.INSIGHTS_PAGE renders exactly 5 Tabs.Screens, with only the hidden route swapped.
What alternative solutions did you explore? (Optional)
Clear the menu or reuse items before adding them in TabsContainer (as a couple of the proposals above suggest). It's already there: menu.clear() runs before re-adding and getOrCreateMenuItemForFragment uses findItem first (MenuHelpers.kt#L7-L12). The extra item comes from tabsModel, not the menu.
JS-only: keep all 6 Tabs.Screens mounted and let RNScreens hide the hidden one, so a beta flip never adds or removes a native tab. RNScreens has no prop to hide a single Android menu item, so this needs a native patch anyway and does more than the fix above.
Remount the whole Tab.Navigator (key it on tabWithoutBarItem) so the host is recreated through removeAllViews, which works. It stops the crash, but every flip resets the nested split navigators' state, and it's only a workaround for the broken removal.
changed the title [-][$175] [Sentry: APP-N5H] HybridApp Android: native tab bar crashes with more than 6 items[/-][+][$250] [Sentry: APP-N5H] HybridApp Android: native tab bar crashes with more than 6 items[/+]on Oct 23, 2026
Please re-state the problem that we are trying to solve in this issue.
On Android HybridApp the app crashes (fatal, UncaughtExceptionHandler) inside the native tab bar with:
IllegalArgumentException: Maximum number of items supported by CustomBottomNavigationView is 6
com.swmansion.rnscreens.gamma.tabs.container.TabsContainer.updateNavigationMenuStructure (TabsContainer.kt:545)
com.swmansion.rnscreens.gamma.tabs.container.MenuHelpersKt.getOrCreateMenuItemForFragment (MenuHelpers.kt:8)
androidx.appcompat.view.menu.MenuBuilder.add
The native Material bottom navigation (the new RNScreens "gamma" native tabs introduced with the liquid‑glass bottom bar, #101339) tries to build a 7th menu item, but CustomBottomNavigationView caps the menu at 6. The crash happens on re‑attach of the tab container, which is why it is intermittent.
What is the root cause of that problem?
The native tab model (TabsContainer.tabsModel) accumulates a stale tab fragment that was logically removed on the JS side but never detached on Android. Once tabsModel holds 7 fragments, the next re‑attach rebuilds the menu and MenuBuilder.add throws on the 7th item.
1. The App drives tabs in and out of the native host. The native bar can show at most 5 of the App's 6 tabs, and which tab has no bar item depends on the Insights beta (Insights with it, Account/Settings without it). The App implements this by giving the hidden route no Tabs.Screen at all (react‑navigation patch 003), so when the beta resolves — or a tab route is re‑keyed for a remount — React Navigation removes one Tabs.Screen and adds another on the native host. The hidden route is chosen here:
The TAB_NAVIGATOR is also unmounted/remounted by the root‑stack slicing optimization, which re‑attaches the native host (this is exactly the path in the crashing stack: onAttachedToWindow → flushPendingUpdates → updateNavigationMenuStructure):
2. RNScreens never removes the old Android tab. On Android, TabsHostViewManager does not override getChildCount/getChildAt, so Fabric sees the TabsHost's raw children (just the single TabsContainer) instead of the logical TabsScreen children it tracks in renderedScreens. When Fabric tries to remove a TabsScreen, its removeViewAt finds no child at that index ("view already removed from parent!") and skipsTabsHost.unmountReactSubviewAt, while the matching insert goes through. So renderedScreens and container.tabsModel keep the removed fragment and grow by one on every swap/remount. This exact defect is documented by the App's own react‑navigation patch 004, whose note says the complete fix belongs in RNScreens:
- Reason: Identifies each native tab by its route name instead of its route key. The App gives the focused tab route a new key on purpose when it pre-inserts a screen under the RHP (`markFocusedTabRouteForRemount` in `GetStateForActionHandlers.ts`, #90985), so the split navigator remounts without a push-transition flash. Keyed by route key, that new key replaced the whole `Tabs.Screen`. Android never removes the old one: `TabsHostViewManager` does not override `getChildAt`/`getChildCount`, so Fabric's `removeViewAt` finds no child at that index ("view already removed from parent!") and skips `TabsHost.unmountReactSubviewAt`, while the insert goes through. The bar then shows the tab twice, and the stale copy opens a blank page. With this patch the native tab (`key`, `screenKey`, `navStateRequest.selectedScreenKey` and the selection events) uses the route name, which stays the same, and only the tab's content is keyed by the route key, so a re-keyed route still remounts its content inside the same native tab. **Remove this patch** once react-native-screens removes Android tabs correctly and React Navigation's native tab view no longer recreates a tab when its route key changes.
- Upstream PR/issue: not reported yet. The Android removal bug belongs to react-native-screens (`TabsHostViewManager`).
Patch 004 only neutralized one trigger (the deliberate route‑key change under markFocusedTabRouteForRemount). The hidden↔visible swap driven by getTabWithoutBarItem (and plain TAB_NAVIGATOR remounts) is a different add/remove on the native host, and that removal is still dropped on Android — so fragments still pile up.
3. The insert guard doesn't catch it; the menu rebuild does.mountReactSubviewAt only guards index < maxItemCount, and inserts always happen at a low index, so the overflow is invisible at insert time. It only surfaces when the container flushes the whole model to the menu. updateNavigationMenuStructure clears the menu and re‑adds one item per fragment in tabsModel, so with 7 fragments the 7th menu.add throws. The native rebuild loop (RNScreens 4.28.0, TabsContainer.kt):
menu.clear()
tabsModel.forEach { fragment ->
menu.getOrCreateMenuItemForFragment(fragment) // MenuBuilder.add -> throws on #7
}
In short: the App legitimately swaps which tab has a bar item, Android fails to detach the swapped‑out TabsScreen, tabsModel creeps from 5 → 6 → 7, and the next re‑attach overflows Material's 6‑item ceiling.
What changes do you think we should make in order to solve the problem?
Fix the actual defect — RNScreens not detaching Android tab children — with a new react-native-screens patch, the same mechanism the App already uses for this native tab bar (patches 001‑005 under patches/react-native-screens/). This is the fix the App's patch‑004 note explicitly defers to ("The Android removal bug belongs to react-native-screens (TabsHostViewManager)").
The TabsHost already tracks its logical children in renderedScreens: ArrayList<TabsScreen> and mutates it in lockstep with the container in mountReactSubviewAt / unmountReactSubviewAt. The only missing piece is making the view manager report those logical children to Fabric, so Fabric can locate a TabsScreen by index and actually route the removal through unmountReactSubviewAt (which detaches it from container.tabsModel). This is exactly how RNScreens' other hosts (ScreenContainer, ScreenStack) override these methods.
Add a new patch, e.g. patches/react-native-screens/react-native-screens+4.28.0+006+android-remove-stale-tab-children.patch, that:
Exposes the logical children on TabsHost (host/TabsHost.kt) with small internal accessors over the existing renderedScreens list:
Overrides the child‑reconciliation hooks in the view manager (host/TabsHostViewManager.kt) so Fabric reconciles against the TabsScreen children instead of the single container view:
With these overrides, when React Navigation removes a TabsScreen (hidden↔visible swap, remount, or re‑key), Fabric finds the child at that index and calls removeViewAt → unmountReactSubviewAt, which removes the fragment from container.tabsModel. tabsModel then stays equal to the real number of rendered tabs (≤ 6), so updateNavigationMenuStructure never attempts a 7th menu.add and the crash cannot occur. Document the new patch in patches/react-native-screens/details.md with the E/App issue and note it can be removed once RNScreens ships the upstream fix.
This should also be reported upstream to software-mansion/react-native-screens as the TabsHostViewManager missing getChildCount/getChildAt overrides, so the patch can be dropped on a future bump and the related react‑navigation patch 004 can be simplified.
🤖 ProposalPolice™ is tracking duplicate proposals for this issue using an OpenAI Conversation. This comment stores that Conversation's ID and can be safely ignored.
When HybridApp Android opens a screen over the tabs (Sentry sample Settings_Troubleshoot) and ScreenStack later re-attaches the tab container, the app fatals with IllegalArgumentException: Maximum number of items supported by CustomBottomNavigationView is 6. The user is kicked out of the session.
The App is already on one native Material tab bar. NativeTabBarShadow/index.tsx only paints a non-interactive shadow, useTabRootScreenWrapperProps/index.android.tsx only inserts androidNativeTabBarSpacer, and getFloatingButtonsBottom only offsets FABs with androidNativeTabBarFloatingButtonsBottom. That chrome does not create menu items, and it stays mounted under the stack.
/** Material's bar row (androidNativeTabBarHeight) plus the 16 dp Material keeps between a FAB and the bar. */
androidNativeTabBarFloatingButtonsBottom: 96,
/** UITabBar's row above the home indicator inset, plus the gap to the floating buttons. */
The throw is the re-attach path in the Sentry stack: ScreenStack.onUpdate -> TabsContainer.onAttachedToWindow -> flushPendingUpdates -> updateNavigationMenuStructure -> getOrCreateMenuItemForFragment -> MenuBuilder.add. The bar already holds the original tabs (max 6). Re-attach still adds a menu item for a fragment that is already in the bar, so add runs with size 6 and the 7th item kills the process.
What changes do you think we should make in order to solve the problem?
Leave NativeTabBarShadow/index.tsx, androidNativeTabBarSpacer, and getFloatingButtonsBottom unchanged. They only layout the existing bar.
Patch getOrCreateMenuItemForFragment in react-native-screens (MenuHelpers.kt, the frame that calls MenuBuilder.add). Today a re-attach still adds a new item once the fragment is not reused. Refuse the add when the menu is already at CustomBottomNavigationView's max of 6:
That stops the fatal at the exact add call in APP-N5H. Duplicate fragments from onAttachedToWindow can no longer push the bar to 7 items.
Ship it as a new sequenced patch under patches/react-native-screens so HybridApp Android picks it up without changing the JS tab chrome.
What alternative solutions did you explore? (Optional)
Make TabsHostViewManager report tab screens from getChildCount / getChildAt so Fabric can unmount stale screens. That targets accumulation, but it does not stop this Sentry path if onAttachedToWindow still adds into a menu that is already full.
Reminder: Please use plain English, be brief and avoid jargon. Feel free to use images, charts or pseudo-code if necessary. Do not post large multi-line diffs or write walls of text. Do not create PRs unless you have been hired for this job.
The App has six tab routes; the native bar shows five. The tab without a bar item gets no Tabs.Screen, so when that tab changes (the Insights beta loading after launch or being toggled), React removes one Tabs.Screen from the native host and inserts another. Before #104238 a re-keyed focused tab route (markFocusedTabRouteForRemount) did the same; both triggers were live in 9.5.13-0:
On Android the removal never reaches react-native-screens. TabsHost keeps its tabs in renderedScreens and hands them to TabsContainer as fragments, so its only real Android child is the container. TabsHostViewManager implements removeViewAt but not getChildAt/getChildCount:
Fabric checks the child with getChildAt before removing it. The default reads the raw Android children, does not find the tab, logs view already removed from parent! and returns, so TabsHost.unmountReactSubviewAt, which drops the fragment from tabsModel, never runs. Inserts have no such check:
Each remove + insert leaves one stale fragment. updateNavigationMenuStructure clears the menu and adds one item per tabsModel entry, so the second change makes 7 and MenuBuilder.add throws. While a page covers the tabs the container is detached and the flush waits for onAttachedToWindow, which is why the stack starts in ScreenStack.onUpdate:
Main now avoids both triggers in JS: the route-name tab key from #104238 (staging 9.5.13-1) and a host remount when the hidden tab changes from #104368 (staging 9.5.16-0, not on production yet). The Android removal itself is unchanged, as the patch 004 note says:
- Reason: Identifies each native tab by its route name instead of its route key. The App gives the focused tab route a new key on purpose when it pre-inserts a screen under the RHP (`markFocusedTabRouteForRemount` in `GetStateForActionHandlers.ts`, #90985), so the split navigator remounts without a push-transition flash. Keyed by route key, that new key replaced the whole `Tabs.Screen`. Android never removes the old one: `TabsHostViewManager` does not override `getChildAt`/`getChildCount`, so Fabric's `removeViewAt` finds no child at that index ("view already removed from parent!") and skips `TabsHost.unmountReactSubviewAt`, while the insert goes through. The bar then shows the tab twice, and the stale copy opens a blank page. With this patch the native tab (`key`, `screenKey`, `navStateRequest.selectedScreenKey` and the selection events) uses the route name, which stays the same, and only the tab's content is keyed by the route key, so a re-keyed route still remounts its content inside the same native tab. **Remove this patch** once react-native-screens removes Android tabs correctly and React Navigation's native tab view no longer recreates a tab when its route key changes.
- Upstream PR/issue: not reported yet. The Android removal bug belongs to react-native-screens (`TabsHostViewManager`).
Back to the tabs: Maximum number of items supported by CustomBottomNavigationView is 6 from MenuHelpers.kt:8 ← TabsContainer.kt:545 ← :212 ← onAttachedToWindow :311 ← ScreenStack.onUpdate (ScreenStack.kt:323), the APP-N5H frames.
On unchanged main the toggles do not crash, but logcat still shows every removal skipped.
What changes do you think we should make in order to solve the problem?
Add react-native-screens+4.28.0+007 so TabsHostViewManager reports renderedScreens to Fabric, as the gamma stack host already does:
- private val renderedScreens: ArrayList<TabsScreen> = arrayListOf()+ internal val renderedScreens: ArrayList<TabsScreen> = arrayListOf()
...
+ override fun getChildAt(parent: TabsHost, index: Int): View? = parent.renderedScreens.getOrNull(index)+ override fun getChildCount(parent: TabsHost): Int = parent.renderedScreens.size
Fabric then reaches unmountReactSubviewAt, and tabsModel matches what JS renders on every remove path. I'd keep the remount and patch 004: TabsContainer.selectedTab is a checkNotNull lookup, so removing the selected tab from a live host still needs them. I have not built the patched APK yet.
What alternative solutions did you explore? (Optional)
Stop adding menu items at 6 in getOrCreateMenuItemForFragment: hides the crash but leaves the stale tab in tabsModel.
The App has six routes but renders five native tabs: the hidden-tab patch omits Tabs.Screen for the hidden route. Earlier builds replaced native tabs when a focused route received a new key or the Insights beta changed which tab was hidden. Current main mitigates these triggers with [stable native tab identity](
- Reason: Identifies each native tab by its route name instead of its route key. The App gives the focused tab route a new key on purpose when it pre-inserts a screen under the RHP (`markFocusedTabRouteForRemount` in `GetStateForActionHandlers.ts`, #90985), so the split navigator remounts without a push-transition flash. Keyed by route key, that new key replaced the whole `Tabs.Screen`. Android never removes the old one: `TabsHostViewManager` does not override `getChildAt`/`getChildCount`, so Fabric's `removeViewAt` finds no child at that index ("view already removed from parent!") and skips `TabsHost.unmountReactSubviewAt`, while the insert goes through. The bar then shows the tab twice, and the stale copy opens a blank page. With this patch the native tab (`key`, `screenKey`, `navStateRequest.selectedScreenKey` and the selection events) uses the route name, which stays the same, and only the tab's content is keyed by the route key, so a re-keyed route still remounts its content inside the same native tab. **Remove this patch** once react-native-screens removes Android tabs correctly and React Navigation's native tab view no longer recreates a tab when its route key changes.
- Upstream PR/issue: not reported yet. The Android removal bug belongs to react-native-screens (`TabsHostViewManager`).
Validate the native boundary with repeated non-selected tab replacements while the host survives, including replacements while detached followed by reattachment. Assert that removed tags disappear and the model/menu retain the expected count. Also verify Android HybridApp expense creation and Insights-beta changes with the existing mitigations retained; mocked JavaScript tab tests cannot exercise Fabric’s removal check.
What alternative solutions did you explore? (Optional)
Clearing the menu is already implemented. Capping menu population would leave stale tabs in the model, while rejecting further insertions would merely move the crash earlier. Correcting child reporting addresses the failed removal itself.
The stack trace shows a seventh native menu entry being added despite Android's six-item limit. A duplicate during tab-container reattachment is plausible but not yet reproduced.
What changes do you think we should make in order to solve the problem?
Instrument tab IDs and native menu counts during attach/update; determine duplicate insertion versus seven distinct tabs, then reconcile entries correctly instead of suppressing the exception.
What alternative solutions did you explore? (Optional)
Avoid a UI-only workaround that masks the symptom without fixing the state or lifecycle problem.
Validation: Test repeated attach/detach and tab switching, including Settings_Troubleshoot.
@mananjadhav I'm available if you need a contributor for this issue. I'll wait for approval before opening a PR.
Activity
melvin-bot commentedon Oct 20, 2026
Triggered auto assignment to Contributor-plus team member for initial proposal review - @mananjadhav (
External)[-][Sentry: APP-N5H] HybridApp Android: native tab bar crashes with more than 6 items[/-][+][$175] [Sentry: APP-N5H] HybridApp Android: native tab bar crashes with more than 6 items[/+]melvin-bot commentedon Oct 20, 2026
Job added to Upwork: https://www.upwork.com/jobs/~022112637848604843209
RajGahoi commentedon Oct 20, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
HybridApp on Android crashes with IllegalArgumentException: Maximum number of items supported by CustomBottomNavigationView is 6 when a screen stack re-attaches the native tab container or when more than 6 navigation items are added.
What is the root cause of that problem?
Android's BottomNavigationView / CustomBottomNavigationView enforces a hard limit of maximum 6 items (MAX_ITEM_COUNT = 6).
In PR #101339 and patch @react-navigation+bottom-tabs+7.19.2+003+hidden-tab-items.patch, the app registers 6 tab routes:
HOME, REPORTS_SPLIT_NAVIGATOR, SEARCH_FULLSCREEN_NAVIGATOR, INSIGHTS, WORKSPACE_NAVIGATOR, SETTINGS_SPLIT_NAVIGATOR.
Although getTabWithoutBarItem designates one route as abBarItemHidden: true to stay at 5 items, when a screen stack re-attaches (ScreenStack.kt:onUpdate -> TabsContainer.kt:onAttachedToWindow -> flushPendingUpdates -> updateNavigationMenuStructure), menu items from the previous fragment attachment can persist or re-accumulate without clearing or recycling if lushPendingUpdates runs repeatedly during stack transitions. Adding the new items pushes the menu size to 7 (or above), throwing IllegalArgumentException: Maximum number of items supported by CustomBottomNavigationView is 6.
What changes do you think we should make in order to solve the problem?
eact-native-screens), before calling updateNavigationMenuStructure / getOrCreateMenuItemForFragment, ensure menu.clear() is called or check that existing menu items matching the fragment tabs are reused/updated rather than re-added.
Automated Tests
Add a test in ScreenStackTest / navigation tests that mounts the native tab navigator, performs stack pushes and pops (such as opening Settings_Troubleshoot), and verifies that the menu items count in BottomNavigationView never exceeds 5.
Contributor details
Your Expensify account email: gahoiraj01@gmail.com
RajGahoi commentedon Oct 20, 2026
Contributor details update:
Upwork Profile Link: https://www.upwork.com/freelancers/~014898525b9c53fc32
jloa-dev commentedon Oct 21, 2026
Contributor details
Your Expensify account email: jloa.dev@gmail.com
Upwork Profile Link: https://www.upwork.com/freelancers/~0163955a2ba221e513
Proposal
Please re-state the problem that we are trying to solve in this issue.
On Android HybridApp, navigating between screens (e.g., visiting
Settings_Troubleshootor during screen transitions inside a ScreenStack) crashes fatally with:IllegalArgumentException: Maximum number of items supported by CustomBottomNavigationView is 6thrown from:
What is the root cause of that problem?
react-native-screens(gamma tabs on Android),TabsContainermanages bottom navigation tabs usingCustomBottomNavigationView(based on Android Material'sBottomNavigationView). Android's bottom navigation menu enforces a strict hardware constraint:MAX_ITEM_COUNT = 6(or 5 standard, 6 custom). Adding a 7th item toMenuBuilderthrowsIllegalArgumentException.ScreenStack.kt:286, when screen fragments are updated or re-appended in stack order, the fragment containing the tab bar is detached and re-attached to the window (transaction.remove(wrapper.fragment)followed bytransaction.add(...)).TabsContainer.onAttachedToWindow()executes, it callsflushPendingUpdates()->updateNavigationMenuStructure().updateNavigationMenuStructure(),TabsContaineriterates through its tab fragments and callsgetOrCreateMenuItemForFragment(fragment)which delegates tobottomNavigationView.menu.add(...).updateNavigationMenuStructure()does not clear or synchronize the existingbottomNavigationView.menuprior to re-populating items. Because items from the initial layout pass are already present in the menu, re-adding the tabs appends duplicate menu items to theMenuBuilder. As soon asmenu.size()reaches 7 (e.g. 4 tabs added twice = 8 items), Android throwsIllegalArgumentException: Maximum number of items supported by CustomBottomNavigationView is 6.What alternative solutions did you explore? (Optional)
None, clearing or diffing existing menu items in
TabsContainer.updateNavigationMenuStructurebefore adding items is the cleanest, idiomatic solution.What changes do you think we should make in order to solve the problem?
Add a patch in
patches/react-native-screens/(or update existing gamma patches, e.g.react-native-screens+4.28.0+006+clear-tab-menu-before-update.patch):In
node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsContainer.kt:Before populating fragments in
updateNavigationMenuStructure(), clear the existing menu:Or in
MenuHelpers.kt:Ensure that
getOrCreateMenuItemForFragmentchecksbottomNavigationView.menu.findItem(fragment.id)instead of unconditionally callingmenu.add(...).What automated tests can you add to prevent this from re-occurring?
Add an Android instrumented/unit test for
TabsContainerverifying that callingonAttachedToWindow()andflushPendingUpdates()repeatedly on aTabsContainerwith 4-5 tabs never causesbottomNavigationView.menu.size()to exceed the fragment count or throwIllegalArgumentException.melvin-bot commentedon Oct 21, 2026
✅ Contributor details stored successfully. Thank you for contributing to Expensify!
sijo0218 commentedon Oct 21, 2026
Contributor details
Your Expensify account email: sijo0218@gmail.com
Upwork Profile Link: https://www.upwork.com/freelancers/~011091133bbb09cd1c
Proposal
Please re-state the problem that we are trying to solve in this issue.
On Android HybridApp, navigating between screens (e.g. visiting sub-pages or during screen transitions in a
ScreenStack) fatal crashes with:thrown from:
What is the root cause of that problem?
There are two interconnected defects in
react-native-screensgamma tabs on Android:Child Removal Failure in Fabric (
TabsHostViewManager):ViewGroupManagermanages view additions and removals by inspecting child views viagetChildCount(parent)andgetChildAt(parent, index).TabsHostViewManager.kt,TabsHostdoes not attachTabsScreenviews directly as AndroidViewGroupchildren (they are managed in an internalrenderedScreenslist and encapsulated inTabsScreenFragmentinsideTabsContainer.tabsModel).TabsHostViewManagerdoes not overridegetChildCountorgetChildAt. Consequently, React Native defaults toparent.childCount(which only sees the rootcontainer, count = 1).index > 0,getChildAt(parent, index)returns out of bounds or mismatches, causing Fabric to consider the view "already removed from parent" and skip callingremoveViewAt/removeView.TabsHost.unmountReactSubviewAtandTabsContainer.removeTabsScreenAtare never called for the old tab. When the tab or replacement screen is re-mounted,TabsHostViewManager.addViewcallsmountReactSubviewAt->container.addTabsScreenAt, appending another fragment intotabsModel.tabsModel, causingtabsModel.sizeto grow beyond 5 to 7 or more.Uncapped Menu Population against Hardware Limits in
updateNavigationMenuStructure():TabsContainer.kt:532-547:menu.clear()on line 543 does clearbottomNavigationView.menu. However,tabsModel.forEachiterates over all items intabsModelwithout checkingbottomNavigationView.maxItemCount(MAX_ITEM_COUNT = 6inCustomBottomNavigationView/ Android MaterialNavigationBarMenu).TabsHost.kt:76,mountReactSubviewAtonly checksindex < bottomNavigationViewMaxItemCount, never checking whetherrenderedScreens.size >= bottomNavigationViewMaxItemCountor whether theTabsScreenis already mounted.ScreenStack.onUpdateexecutes (e.g. re-attaching screens in stack order viatransaction.commitNowAllowingStateLoss()),TabsContainer.onAttachedToWindowcallsflushPendingUpdates()->updateNavigationMenuStructure(). BecausetabsModelaccumulated 7 or more fragments,tabsModel.forEachattempts to add the 7th item intobottomNavigationView.menu.NavigationBarMenu.addInternaldetectssize() + 1 > maxItemCount(7 > 6) and throwsIllegalArgumentException: Maximum number of items supported by CustomBottomNavigationView is 6.What alternative solutions did you explore? (Optional)
Attempting to only cap at the JS layer (
NativeBottomTabView.native.js) is insufficient because Fabric view re-ordering and remount cycles on Android will still leak native fragments insideTabsHost.renderedScreensandTabsContainer.tabsModelifTabsHostViewManagercannot report its children. Both the view manager lifecycle and native container menu bounds must be secured.What changes do you think we should make in order to solve the problem?
Add a patch in
patches/react-native-screens/react-native-screens+4.28.0+006+fix-tabs-host-child-lifecycle-and-menu-limit.patch:In
TabsHostViewManager.kt:Override
getChildCountandgetChildAtto reflectrenderedScreensso Fabric can successfully unmount child screens:In
TabsHost.kt:Expose
renderedScreensCountandgetRenderedScreenAt(index):In
mountReactSubviewAt, guard against duplicate insertion and ensurerenderedScreensdeduplicates any existing entry for the same screen:In
TabsContainer.kt:In
addTabsScreenAt, deduplicate matching screens:In
updateNavigationMenuStructure(), bound the iteration strictly tobottomNavigationView.maxItemCount:What automated tests can you add to prevent this from re-occurring?
TabsContainerTest/TabsHostTest), verify that repeatedly mounting, unmounting, and re-mounting tabs onTabsHostwith Fabric view manager dispatches:renderedScreens.size == tabsModel.size.bottomNavigationView.maxItemCount.IllegalArgumentExceptionduringonAttachedToWindow()andflushPendingUpdates().tests/unit/NativeBottomTabViewTest.tsx, add test cases simulating rapid navigation transitions across tab routes and beta toggles to ensure the number of nativeTabs.Screenchildren mounted toTabs.Hostnever exceeds 5.melvin-bot commentedon Oct 21, 2026
✅ Contributor details stored successfully. Thank you for contributing to Expensify!
3 remaining items
wildan-m commentedon Oct 23, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
On Android HybridApp, the app crashes fatally with
IllegalArgumentException: Maximum number of items supported by CustomBottomNavigationView is 6, thrown while the native tab container rebuilds its bottom navigation menu after being re-attached by a screen stack (Sentry APP-N5H).What is the root cause of that problem?
The native tab bar is react-native-screens'
TabsHost. Tab screens are not regular view children ofTabsHost:mountReactSubviewAtstores eachTabsScreenin an internalrenderedScreenslist and hands it toTabsContainer, which wraps it in a fragment and renders it inside the container's own content view:https://github.com/software-mansion/react-native-screens/blob/2381ed8d72fe19185fc8415cb61df7b79bbf4376/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/TabsHost.kt#L85-L112
When React removes a tab screen, Fabric's
SurfaceMountingManager.removeViewAtfirst verifies the removal: it asks the parent's view manager for the child at that index viagetChildAt, and when the tag does not match, it scans the parent's raw view children for the tag. If the tag is not found there either, it logs "view already removed from parent!" and returns without ever calling the view manager'sremoveViewAt:https://github.com/facebook/react-native/blob/a632f9efe24bac8b3a113c78469948f55bde0f5d/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.kt#L455-L484
TabsHostViewManagerdoes not overridegetChildCount/getChildAt, so the default implementation reads the rawFrameLayoutchildren ofTabsHost— and those contain only the internalTabsContainer, never theTabsScreenviews:https://github.com/software-mansion/react-native-screens/blob/2381ed8d72fe19185fc8415cb61df7b79bbf4376/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/TabsHostViewManager.kt#L33-L56
The result is that on Android, every native removal of a tab screen is silently skipped:
unmountReactSubviewAtnever runs, and the removed screen stays inrenderedScreensand inTabsContainer'stabsModelforever. The app registers exactly six tabs — the maximum the Material bottom navigation view supports. Whenever React recreates the tab screens while theTabsHostview itself survives (a navigation state reset regenerates the route keys, so all six screens are torn down and recreated; the sample Sentry event sits on the Troubleshoot screen, whose "Reset and refresh" option wipes and reloads local app state while preserving the session), the six stale entries remain and the replacements are appended. The size guard inmountReactSubviewAtonly checks the insertion index (always 0–5), not the total size, sotabsModelsilently grows past the cap.The crash then surfaces later, on re-attach:
flushPendingUpdatesis a no-op while the container is detached (for example while a pushed stack screen covers it), so the first menu rebuild runs fromonAttachedToWindow— which is why the stack goes throughScreenStack.onUpdate.updateNavigationMenuStructureclears the menu and re-adds one item pertabsModelentry, and the seventh add throws:https://github.com/software-mansion/react-native-screens/blob/2381ed8d72fe19185fc8415cb61df7b79bbf4376/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsContainer.kt#L532-L547
https://github.com/software-mansion/react-native-screens/blob/2381ed8d72fe19185fc8415cb61df7b79bbf4376/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/MenuHelpers.kt#L7-L13
The defect is still present on the latest react-native-screens nightly (the tabs code moved out of the
gammanamespace, butTabsHostViewManagerstill has nogetChildCount/getChildAtoverrides and the menu rebuild is unchanged), so a library bump does not fix this.What changes do you think we should make in order to solve the problem?
Add a new sequenced patch to
patches/react-native-screens/(with the matchingdetails.mdentry) that lets Fabric see the tab screens as children ofTabsHost, the same way react-native-screens already handles its other fragment-based parents —ScreenStackViewManagerandScreenContainerViewManagerboth overridegetChildCountandgetChildAtto answer from their internal screen lists instead of the raw view children:https://github.com/software-mansion/react-native-screens/blob/2381ed8d72fe19185fc8415cb61df7b79bbf4376/android/src/main/java/com/swmansion/rnscreens/ScreenStackViewManager.kt#L55-L62
Concretely: expose the rendered tab screens from
TabsHostthrough two small internal accessors (the count ofrenderedScreensand the screen at a given index), and overridegetChildCountandgetChildAtinTabsHostViewManagerto delegate to them. With that in place, Fabric's verification inremoveViewAtfinds the expected tag at the expected index and proceeds to call the view manager'sremoveViewAt, sounmountReactSubviewAtruns, the removed screen leavesrenderedScreensandtabsModel, and any later menu rebuild works with exactly the live tabs. The over-capmenu.addcan no longer happen, and stale fragments no longer accumulate across remounts.Since the missing overrides are still present upstream, this should also be reported to software-mansion/react-native-screens, and the patch can be dropped once an upstream release ships the fix.
Compare branch: https://github.com/Expensify/App/compare/main...wildan-m:App:wildan/104505-android-tab-screen-removals?expand=1
What alternative solutions did you explore? (Optional)
Making
updateNavigationMenuStructuredefensive — capping the rebuild at the menu's maximum or deduplicatingtabsModelby screen key — hides the crash but keeps the real defect: the staleTabsScreenFragmententries stay registered, keep participating in selection lookups, and the bar could show items for screens React has already dropped. Similarly, tightening the guard inmountReactSubviewAtto check the total size rather than the insertion index would only turn this crash into a different, earlier one. Fixing the child bookkeeping so removals actually reach the view manager addresses the cause rather than the symptom.David-2002065 commentedon Oct 23, 2026
Proposal
What is the root cause of that problem?
The bar never gets 7 items from a double add.
updateNavigationMenuStructurealready doesmenu.clear()and then adds one item per entry intabsModel(TabsContainer.kt#L532-L547). So the crash meanstabsModelreally holds 7TabsScreens. Native tabs get added but are never removed.The reason is that Android can't remove a native tab.
TabsHostViewManageroverridesremoveViewAtbut notgetChildAt/getChildCount(TabsHostViewManager.kt#L50-L55). Before removing anything, Fabric checks which child is at that index throughviewGroupManager.getChildAt(SurfaceMountingManager.kt#L456-L482). The default returns the real Android child ofTabsHost, which is the container and not aTabsScreen. The tag doesn't match, so Fabric logsview already removed from parent!and returns.TabsHost.unmountReactSubviewAtis never called, but inserts still go throughmountReactSubviewAt(TabsHost.kt#L85-L105). The gamma stack sibling already has these overrides (StackHostViewManager.kt#L52-L57), but the tabs one doesn't.In the App, a tab gets removed and inserted whenever the Insights beta flips. We register 6 tabs, and one of them is marked
tabBarItemHidden: Account with the beta, Insights without it (getTabWithoutBarItem.ts#L8-L10, TabNavigator.native.tsx#L41-L48). The hidden-tab patch rendersnullinstead of aTabs.Screenfor the hidden route (hidden-tab-items.patch#L68-L70). Each flip inserts one native tab and leaves the stale one behind:MenuBuilder.addthrowsThat's why the sample event is on
Settings_Troubleshoot. There are two ways to flip the beta twice from there:insightsPagetwice (DynamicBetaOverridesPage.tsx#L54-L61). This page is only on staging/internal builds, which is why most of the users are on the 9.5.13-0 staging build.BETASisn't inKEYS_TO_PRESERVE(App.ts#L132-L159), so for an Insights user it goes from on to unknown (off) and back to on after OpenApp.The tab container is detached while the RHP covers it, so
flushPendingUpdatesdoesn't run until the stack attaches the container again. That's theScreenStack.onUpdate -> TabsContainer.onAttachedToWindow -> flushPendingUpdatespath in the trace (TabsContainer.kt#L291-L311).This is the same native bug as #104230. #104238 worked around it only for the route key change, by keying native tabs by route name (patch 004). That patch landed in 9.5.13-1, which is why 9.5.13-0 has most of the events. A hidden/visible swap still adds and removes a real
Tabs.Screen, so 9.5.13-1, 9.5.13-3 and 9.5.14-0 still crash.What changes do you think we should make in order to solve the problem?
Fix the removal itself so Fabric reaches
unmountReactSubviewAt. Add a new patch,react-native-screens+4.28.0+006+fix-android-tabs-host-child-removal.patch, that givesTabsHostViewManagerthe same overridesStackHostViewManagerhas.In
TabsHost.kt, expose the rendered screens:In
TabsHostViewManager.kt:Now Fabric finds the matching tag at that index and calls
removeViewAt->unmountReactSubviewAt, sotabsModelstays in sync with what JS renders. The beta flip ends with 5 items, the stale extra tab is gone, and the menu can't reach 7. Nothing changes on iOS, and we don't need to touch the JS hidden-tab logic. I'd keep patch 004 because it still prevents the remount flash, but its "Remove this patch once react-native-screens removes Android tabs correctly" note indetails.mdwould then be satisfied for the Android part. I'd also report it upstream, since StackHost already has the fix.For tests, the bug is native, so a jest test can't reach it. I'll cover it with a manual QA step on Android: toggle
insightsPagein Beta overrides 3 times and go back, then do Clear cache and restart as an Insights user, and check that the bar always shows exactly 5 tabs without crashing. I'll also add a jest test for the JS contract we rely on: flippingCONST.BETAS.INSIGHTS_PAGErenders exactly 5Tabs.Screens, with only the hidden route swapped.What alternative solutions did you explore? (Optional)
TabsContainer(as a couple of the proposals above suggest). It's already there:menu.clear()runs before re-adding andgetOrCreateMenuItemForFragmentusesfindItemfirst (MenuHelpers.kt#L7-L12). The extra item comes fromtabsModel, not the menu.Tabs.Screens mounted and let RNScreens hide the hidden one, so a beta flip never adds or removes a native tab. RNScreens has no prop to hide a single Android menu item, so this needs a native patch anyway and does more than the fix above.Tab.Navigator(key it ontabWithoutBarItem) so the host is recreated throughremoveAllViews, which works. It stops the crash, but every flip resets the nested split navigators' state, and it's only a workaround for the broken removal.[-][$175] [Sentry: APP-N5H] HybridApp Android: native tab bar crashes with more than 6 items[/-][+][$250] [Sentry: APP-N5H] HybridApp Android: native tab bar crashes with more than 6 items[/+]abbasifaizan70 commentedon Oct 23, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
On Android HybridApp the app crashes (fatal,
UncaughtExceptionHandler) inside the native tab bar with:The native Material bottom navigation (the new RNScreens "gamma" native tabs introduced with the liquid‑glass bottom bar, #101339) tries to build a 7th menu item, but
CustomBottomNavigationViewcaps the menu at 6. The crash happens on re‑attach of the tab container, which is why it is intermittent.What is the root cause of that problem?
The native tab model (
TabsContainer.tabsModel) accumulates a stale tab fragment that was logically removed on the JS side but never detached on Android. OncetabsModelholds 7 fragments, the next re‑attach rebuilds the menu andMenuBuilder.addthrows on the 7th item.1. The App drives tabs in and out of the native host. The native bar can show at most 5 of the App's 6 tabs, and which tab has no bar item depends on the Insights beta (Insights with it, Account/Settings without it). The App implements this by giving the hidden route no
Tabs.Screenat all (react‑navigation patch 003), so when the beta resolves — or a tab route is re‑keyed for a remount — React Navigation removes oneTabs.Screenand adds another on the native host. The hidden route is chosen here:App/src/libs/Navigation/AppNavigator/Navigators/NativeTabNavigator/getTabWithoutBarItem.ts
Lines 8 to 10 in 16d77a9
The six registered tabs and the hidden‑item option that is applied to the swapped‑out tab:
App/src/libs/Navigation/AppNavigator/Navigators/TabNavigator.native.tsx
Line 33 in 16d77a9
App/src/libs/Navigation/AppNavigator/Navigators/TabNavigator.native.tsx
Lines 59 to 84 in 16d77a9
The
TAB_NAVIGATORis also unmounted/remounted by the root‑stack slicing optimization, which re‑attaches the native host (this is exactly the path in the crashing stack:onAttachedToWindow→flushPendingUpdates→updateNavigationMenuStructure):App/src/libs/Navigation/AppNavigator/createRootStackNavigator/useCustomRootStackNavigatorState/index.ts
Lines 7 to 22 in 16d77a9
2. RNScreens never removes the old Android tab. On Android,
TabsHostViewManagerdoes not overridegetChildCount/getChildAt, so Fabric sees theTabsHost's raw children (just the singleTabsContainer) instead of the logicalTabsScreenchildren it tracks inrenderedScreens. When Fabric tries to remove aTabsScreen, itsremoveViewAtfinds no child at that index ("view already removed from parent!") and skipsTabsHost.unmountReactSubviewAt, while the matching insert goes through. SorenderedScreensandcontainer.tabsModelkeep the removed fragment and grow by one on every swap/remount. This exact defect is documented by the App's own react‑navigation patch 004, whose note says the complete fix belongs in RNScreens:App/patches/react-navigation/details.md
Lines 84 to 85 in 16d77a9
Patch 004 only neutralized one trigger (the deliberate route‑key change under
markFocusedTabRouteForRemount). The hidden↔visible swap driven bygetTabWithoutBarItem(and plainTAB_NAVIGATORremounts) is a different add/remove on the native host, and that removal is still dropped on Android — so fragments still pile up.3. The insert guard doesn't catch it; the menu rebuild does.
mountReactSubviewAtonly guardsindex < maxItemCount, and inserts always happen at a low index, so the overflow is invisible at insert time. It only surfaces when the container flushes the whole model to the menu.updateNavigationMenuStructureclears the menu and re‑adds one item per fragment intabsModel, so with 7 fragments the 7thmenu.addthrows. The native rebuild loop (RNScreens 4.28.0,TabsContainer.kt):menu.clear() tabsModel.forEach { fragment -> menu.getOrCreateMenuItemForFragment(fragment) // MenuBuilder.add -> throws on #7 }In short: the App legitimately swaps which tab has a bar item, Android fails to detach the swapped‑out
TabsScreen,tabsModelcreeps from 5 → 6 → 7, and the next re‑attach overflows Material's 6‑item ceiling.What changes do you think we should make in order to solve the problem?
Fix the actual defect — RNScreens not detaching Android tab children — with a new
react-native-screenspatch, the same mechanism the App already uses for this native tab bar (patches 001‑005 underpatches/react-native-screens/). This is the fix the App's patch‑004 note explicitly defers to ("The Android removal bug belongs to react-native-screens (TabsHostViewManager)").The
TabsHostalready tracks its logical children inrenderedScreens: ArrayList<TabsScreen>and mutates it in lockstep with the container inmountReactSubviewAt/unmountReactSubviewAt. The only missing piece is making the view manager report those logical children to Fabric, so Fabric can locate aTabsScreenby index and actually route the removal throughunmountReactSubviewAt(which detaches it fromcontainer.tabsModel). This is exactly how RNScreens' other hosts (ScreenContainer,ScreenStack) override these methods.Add a new patch, e.g.
patches/react-native-screens/react-native-screens+4.28.0+006+android-remove-stale-tab-children.patch, that:TabsHost(host/TabsHost.kt) with small internal accessors over the existingrenderedScreenslist:host/TabsHostViewManager.kt) so Fabric reconciles against theTabsScreenchildren instead of the single container view:With these overrides, when React Navigation removes a
TabsScreen(hidden↔visible swap, remount, or re‑key), Fabric finds the child at that index and callsremoveViewAt→unmountReactSubviewAt, which removes the fragment fromcontainer.tabsModel.tabsModelthen stays equal to the real number of rendered tabs (≤ 6), soupdateNavigationMenuStructurenever attempts a 7thmenu.addand the crash cannot occur. Document the new patch inpatches/react-native-screens/details.mdwith the E/App issue and note it can be removed once RNScreens ships the upstream fix.This should also be reported upstream to
software-mansion/react-native-screensas theTabsHostViewManagermissinggetChildCount/getChildAtoverrides, so the patch can be dropped on a future bump and the related react‑navigation patch 004 can be simplified.github-actions commentedon Oct 23, 2026
🤖 ProposalPolice™ is tracking duplicate proposals for this issue using an OpenAI Conversation. This comment stores that Conversation's ID and can be safely ignored.
samranahm commentedon Oct 23, 2026
Proposal
What is the root cause of that problem?
When HybridApp Android opens a screen over the tabs (Sentry sample
Settings_Troubleshoot) andScreenStacklater re-attaches the tab container, the app fatals withIllegalArgumentException: Maximum number of items supported by CustomBottomNavigationView is 6. The user is kicked out of the session.The App is already on one native Material tab bar.
NativeTabBarShadow/index.tsxonly paints a non-interactive shadow,useTabRootScreenWrapperProps/index.android.tsxonly insertsandroidNativeTabBarSpacer, andgetFloatingButtonsBottomonly offsets FABs withandroidNativeTabBarFloatingButtonsBottom. That chrome does not create menu items, and it stays mounted under the stack.App/src/libs/Navigation/AppNavigator/Navigators/NativeTabNavigator/NativeTabBarShadow/index.tsx
Lines 14 to 15 in de7716f
App/src/components/Navigation/TabBarBottomContent/useTabRootScreenWrapperProps/index.android.tsx
Lines 23 to 29 in de7716f
App/src/libs/Navigation/AppNavigator/Navigators/NativeTabNavigator/useNativeTabBarOptions/index.android.ts
Line 18 in de7716f
App/src/styles/variables.ts
Lines 138 to 140 in de7716f
The throw is the re-attach path in the Sentry stack:
ScreenStack.onUpdate->TabsContainer.onAttachedToWindow->flushPendingUpdates->updateNavigationMenuStructure->getOrCreateMenuItemForFragment->MenuBuilder.add. The bar already holds the original tabs (max 6). Re-attach still adds a menu item for a fragment that is already in the bar, soaddruns with size 6 and the 7th item kills the process.What changes do you think we should make in order to solve the problem?
Leave
NativeTabBarShadow/index.tsx,androidNativeTabBarSpacer, andgetFloatingButtonsBottomunchanged. They only layout the existing bar.getOrCreateMenuItemForFragmentin react-native-screens (MenuHelpers.kt, the frame that callsMenuBuilder.add). Today a re-attach still adds a new item once the fragment is not reused. Refuse the add when the menu is already atCustomBottomNavigationView's max of 6:That stops the fatal at the exact
addcall in APP-N5H. Duplicate fragments fromonAttachedToWindowcan no longer push the bar to 7 items.Ship it as a new sequenced patch under
patches/react-native-screensso HybridApp Android picks it up without changing the JS tab chrome.What alternative solutions did you explore? (Optional)
Make
TabsHostViewManagerreport tab screens fromgetChildCount/getChildAtso Fabric can unmount stale screens. That targets accumulation, but it does not stop this Sentry path ifonAttachedToWindowstill adds into a menu that is already full.Reminder: Please use plain English, be brief and avoid jargon. Feel free to use images, charts or pseudo-code if necessary. Do not post large multi-line diffs or write walls of text. Do not create PRs unless you have been hired for this job.
mananjadhav commentedon Oct 23, 2026
@wildan-m's proposal is good to go.
🎀 👀 🎀 C+ reviewed.
melvin-bot commentedon Oct 23, 2026
Current assignee @mountiny is eligible for the choreEngineerContributorManagement assigner, not assigning anyone new.
yusufdeveloper2903 commentedon Oct 23, 2026
Proposal
What is the root cause of that problem?
The App has six tab routes; the native bar shows five. The tab without a bar item gets no
Tabs.Screen, so when that tab changes (the Insights beta loading after launch or being toggled), React removes oneTabs.Screenfrom the native host and inserts another. Before #104238 a re-keyed focused tab route (markFocusedTabRouteForRemount) did the same; both triggers were live in 9.5.13-0:App/patches/react-navigation/@react-navigation+bottom-tabs+7.19.2+003+hidden-tab-items.patch
Lines 87 to 92 in de7716f
On Android the removal never reaches react-native-screens.
TabsHostkeeps its tabs inrenderedScreensand hands them toTabsContaineras fragments, so its only real Android child is the container.TabsHostViewManagerimplementsremoveViewAtbut notgetChildAt/getChildCount:https://github.com/software-mansion/react-native-screens/blob/42788c197e817ebfe21c0f5d36e0b0e02df4950e/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/TabsHostViewManager.kt#L50-L59
Fabric checks the child with
getChildAtbefore removing it. The default reads the raw Android children, does not find the tab, logsview already removed from parent!and returns, soTabsHost.unmountReactSubviewAt, which drops the fragment fromtabsModel, never runs. Inserts have no such check:https://github.com/facebook/react-native/blob/72258ddf7b0b795bbafcbeb5930620b6500c7a06/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.kt#L456-L482
Each remove + insert leaves one stale fragment.
updateNavigationMenuStructureclears the menu and adds one item pertabsModelentry, so the second change makes 7 andMenuBuilder.addthrows. While a page covers the tabs the container is detached and the flush waits foronAttachedToWindow, which is why the stack starts inScreenStack.onUpdate:https://github.com/software-mansion/react-native-screens/blob/42788c197e817ebfe21c0f5d36e0b0e02df4950e/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsContainer.kt#L532-L547
Main now avoids both triggers in JS: the route-name tab key from #104238 (staging 9.5.13-1) and a host remount when the hidden tab changes from #104368 (staging 9.5.16-0, not on production yet). The Android removal itself is unchanged, as the patch 004 note says:
App/patches/react-navigation/details.md
Lines 82 to 88 in de7716f
App/src/libs/Navigation/AppNavigator/Navigators/NativeTabNavigator/NativeTabLayout.tsx
Lines 19 to 34 in de7716f
I reproduced it on dev Android with that remount
keyremoved (the JS production 9.5.13-6 onward still ships) and watched logcat:insightsPageon:removeViewAt: [2542] -> [2544] @4: view already removed from parent!insightsPageoff:removeViewAt: [6324] -> [2544] @3: view already removed from parent!Maximum number of items supported by CustomBottomNavigationView is 6fromMenuHelpers.kt:8←TabsContainer.kt:545←:212←onAttachedToWindow :311←ScreenStack.onUpdate (ScreenStack.kt:323), the APP-N5H frames.On unchanged main the toggles do not crash, but logcat still shows every removal skipped.
What changes do you think we should make in order to solve the problem?
Add
react-native-screens+4.28.0+007soTabsHostViewManagerreportsrenderedScreensto Fabric, as the gamma stack host already does:https://github.com/software-mansion/react-native-screens/blob/42788c197e817ebfe21c0f5d36e0b0e02df4950e/android/src/main/java/com/swmansion/rnscreens/gamma/stack/host/StackHostViewManager.kt#L52-L57
Fabric then reaches
unmountReactSubviewAt, andtabsModelmatches what JS renders on every remove path. I'd keep the remount and patch 004:TabsContainer.selectedTabis acheckNotNulllookup, so removing the selected tab from a live host still needs them. I have not built the patched APK yet.What alternative solutions did you explore? (Optional)
getOrCreateMenuItemForFragment: hides the crash but leaves the stale tab intabsModel.nabi-ebrahimi commentedon Oct 23, 2026
Proposal
What is the root cause of that problem?
Android skips native tab removals, so stale tabs accumulate in
TabsContainer.tabsModeluntil rebuilding the menu exceeds its six-item limit.TabsHoststores its logical tab children inrenderedScreens; its only direct Android child is the internal container. However,TabsHostViewManagerimplements additions and removals without overridinggetChildAtorgetChildCount. Fabric therefore inspects the wrong children, cannot find the tab’s tag, and returns before callingremoveViewAt. ([TabsHost](https://github.com/software-mansion/react-native-screens/blob/2381ed8d72fe19185fc8415cb61df7b79bbf4376/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/TabsHost.kt#L32-L64), [view manager](https://github.com/software-mansion/react-native-screens/blob/2381ed8d72fe19185fc8415cb61df7b79bbf4376/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/TabsHostViewManager.kt#L33-L59), [Fabric removal check](https://github.com/react/react-native/blob/a632f9efe24bac8b3a113c78469948f55bde0f5d/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.kt#L453-L505))Replacement tabs still reach
mountReactSubviewAt, while the old tabs never reachunmountReactSubviewAt. The insertion guard checks the insertion index, not the accumulated count. Starting with five native tabs, two replacements can therefore leave seven entries. ([Mount/unmount implementation](https://github.com/software-mansion/react-native-screens/blob/2381ed8d72fe19185fc8415cb61df7b79bbf4376/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/TabsHost.kt#L85-L104))updateNavigationMenuStructurealready clears the menu, then adds one item per model entry. The seventh entry causes the exception. Updates wait while the container is detached and resume inonAttachedToWindow, explaining the reattachment path in the reported stack. Reattachment without accumulated stale tabs does not increase the menu count. ([Menu rebuild](https://github.com/software-mansion/react-native-screens/blob/2381ed8d72fe19185fc8415cb61df7b79bbf4376/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsContainer.kt#L532-L547), [attachment handling](https://github.com/software-mansion/react-native-screens/blob/2381ed8d72fe19185fc8415cb61df7b79bbf4376/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsContainer.kt#L291-L311))The App has six routes but renders five native tabs: the hidden-tab patch omits
Tabs.Screenfor the hidden route. Earlier builds replaced native tabs when a focused route received a new key or the Insights beta changed which tab was hidden. Current main mitigates these triggers with [stable native tab identity](App/patches/react-navigation/details.md
Lines 82 to 88 in ba97c03
App/src/libs/Navigation/AppNavigator/Navigators/NativeTabNavigator/NativeTabLayout.tsx
Lines 19 to 35 in ba97c03
What changes do you think we should make in order to solve the problem?
Add a sequenced
react-native-screenspatch that exposes read-only accessors forrenderedScreensand overridesTabsHostViewManager.getChildCountandgetChildAtto use them. Follow the existing [gamma stack host implementation](https://github.com/software-mansion/react-native-screens/blob/2381ed8d72fe19185fc8415cb61df7b79bbf4376/android/src/main/java/com/swmansion/rnscreens/gamma/stack/host/StackHostViewManager.kt#L52-L57), including nullable lookup for an invalid index.Fabric can then find the intended child and execute the existing removal, keeping
renderedScreensandtabsModelsynchronized with React.Keep the current stable-identity patch and host-remount behavior. Correct child reporting alone does not make removing the selected tab safe:
selectedTabrequires that tab to remain in the model.Validate the native boundary with repeated non-selected tab replacements while the host survives, including replacements while detached followed by reattachment. Assert that removed tags disappear and the model/menu retain the expected count. Also verify Android HybridApp expense creation and Insights-beta changes with the existing mitigations retained; mocked JavaScript tab tests cannot exercise Fabric’s removal check.
What alternative solutions did you explore? (Optional)
Clearing the menu is already implemented. Capping menu population would leave stale tabs in the model, while rejecting further insertions would merely move the crash earlier. Correcting child reporting addresses the failed removal itself.
bconnnnn commentedon Oct 23, 2026
Proposal
What is the root cause of that problem?
The stack trace shows a seventh native menu entry being added despite Android's six-item limit. A duplicate during tab-container reattachment is plausible but not yet reproduced.
What changes do you think we should make in order to solve the problem?
Instrument tab IDs and native menu counts during attach/update; determine duplicate insertion versus seven distinct tabs, then reconcile entries correctly instead of suppressing the exception.
What alternative solutions did you explore? (Optional)
Avoid a UI-only workaround that masks the symptom without fixing the state or lifecycle problem.
Validation: Test repeated attach/detach and tab switching, including Settings_Troubleshoot.
@mananjadhav I'm available if you need a contributor for this issue. I'll wait for approval before opening a PR.
melvin-bot commentedon Oct 23, 2026
❌ There was an error making the offer to @wildan-m for the Contributor role. The BZ member will need to manually hire the contributor.