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
Error: IllegalStateException: FragmentManager is already executing transactions
Suspected cause
Legacy OldDot (yapl) NavigationManager calls commitNowAllowingStateLoss while FragmentManager is already executing another transaction. Likely two navigation commands (dismissModal and popLastPage) firing back-to-back without waiting for the first to finish.
Reproduction
Unknown — see Sentry events linked from the Sentry issue.
changed the title [-][Sentry: APP-MDA] FragmentManager race in legacy OldDot navigation (yapl)[/-][+][$175] [Sentry: APP-MDA] FragmentManager race in legacy OldDot navigation (yapl)[/+]on Oct 1, 2026
This appears to be a backend/internal issue. A separate internal investigation is needed.
Why: Every first-party frame in the stack trace is in the legacy OldDot native navigation layer. That code is not in the App repo, so contributors cannot fix it here. I found no App code path that sends these navigation commands.
Next step: An internal engineer with access to that code should take this. The External label and Upwork job likely don't fit, since contributors can't reach the code.
changed the title [-][$175] [Sentry: APP-MDA] FragmentManager race in legacy OldDot navigation (yapl)[/-][+][$250] [Sentry: APP-MDA] FragmentManager race in legacy OldDot navigation (yapl)[/+]on Oct 1, 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.
@ZhenjaHorbach Thanks for picking this up! When you get to it, could you take a look at my proposal? It's grounded in the AndroidX FragmentManager source directly and keeps the fix self-contained to this repo.
OldDot navigation on Android (PageNavigator) commits every page change synchronously with commitNowAllowingStateLoss() (popLastPage, popAllPages, pushPage). When a navigation (e.g. popLastPage triggered by a network response) runs while the previous page's exit animation is still in progress, AndroidX cancels that animation and destroys the page inside the running transaction. BaseViewController.onDestroy calls into JS, and the page's JS onDestroy navigates again synchronously: FixExpenseViolationsController.onDestroy -> endViolationFixingFlow -> NavigationManager.dismissModal. So a second commit starts while the first one is still executing -> IllegalStateException: FragmentManager is already executing transactions. The exception is thrown inside a JNI callback (yaplNavigationManager.handleCommand), so JSC aborts the app (SIGABRT). Sentry also shows the same nested pattern from YaplActivityBase.onResume -> yaplOpenNewApp -> popAllPages.
Solution
Make PageNavigator re-entrancy safe instead of patching each JS onDestroy. It tracks when a fragment commit is in progress, and any navigation command (push/pop/dismiss) that arrives during that time is deferred to the next main-loop tick instead of being committed in a nested way. Normal navigation is unchanged; only the case that crashes today gets delayed by one tick. This covers both crash patterns in Sentry and any other page whose onDestroy/lifecycle callback navigates.
Verdict: The approach is sound for the crash in the stack trace. Add a fallback, though, because a navigator-owned flag won't catch every nested commit.
I couldn't read the native code or Sentry from here, so I checked the plan against the public AndroidX source only.
AndroidX also sets the executing state during lifecycle dispatch, such as pause, stop and destroyView (#L3292-L3305). Your flag won't see those. Catch this IllegalStateException around the commit and post the command as a fallback.
Once a command is queued, queue every later command too, and drain in order. Otherwise a newer command can run before an older deferred one.
Make deferred pop and dismiss idempotent. The deferred dismiss runs after the outer pop, so it could remove one page too many.
Defer only commands that return nothing to JS.
Clear the queue when the activity is destroyed. AndroidX silently drops these commits during teardown (#L1951-L1955).
To reproduce: Set Animator duration scale to 10x in Developer options. Then trigger the second navigation while the exit animation runs.
Activity
melvin-bot commentedon Oct 1, 2026
Triggered auto assignment to Contributor-plus team member for initial proposal review - @sobitneupane (
External)[-][Sentry: APP-MDA] FragmentManager race in legacy OldDot navigation (yapl)[/-][+][$175] [Sentry: APP-MDA] FragmentManager race in legacy OldDot navigation (yapl)[/+]melvin-bot commentedon Oct 1, 2026
Job added to Upwork: https://www.upwork.com/jobs/~022105599553938368492
MelvinBot commentedon Oct 1, 2026
Issue Analysis
This appears to be a backend/internal issue. A separate internal investigation is needed.
Why: Every first-party frame in the stack trace is in the legacy OldDot native navigation layer. That code is not in the App repo, so contributors cannot fix it here. I found no App code path that sends these navigation commands.
Next step: An internal engineer with access to that code should take this. The
Externallabel and Upwork job likely don't fit, since contributors can't reach the code.I found no duplicate open issues.
view run
[-][$175] [Sentry: APP-MDA] FragmentManager race in legacy OldDot navigation (yapl)[/-][+][$250] [Sentry: APP-MDA] FragmentManager race in legacy OldDot navigation (yapl)[/+]Dip-G-Git commentedon Oct 1, 2026
github-actions commentedon Oct 1, 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.
44 remaining items
melvin-bot commentedon Oct 7, 2026
Triggered auto assignment to Contributor-plus team member for initial proposal review - @ZhenjaHorbach (
External)mountiny commentedon Oct 7, 2026
@ZhenjaHorbach can you please take a look into this one? Thank you.
ZhenjaHorbach commentedon Oct 7, 2026
Will check tomorrow morning!
amar-sheikh commentedon Oct 7, 2026
@ZhenjaHorbach Thanks for picking this up! When you get to it, could you take a look at my proposal? It's grounded in the AndroidX FragmentManager source directly and keeps the fix self-contained to this repo.
ZhenjaHorbach commentedon Oct 8, 2026
@mountiny
Just worried about this issue
Should we find somebody from the agencies, since they have access to OldDot?
mountiny commentedon Oct 9, 2026
Can you post in the expert contributors channel to look for volunteers? You can tag Marcin
melvin-bot commentedon Oct 13, 2026
@ZhenjaHorbach Huh... This is 4 days overdue. Who can take care of this?
ZhenjaHorbach commentedon Oct 14, 2026
@suneox
I think you can start working on this in any case!
suneox commentedon Oct 15, 2026
Root cause and fix plan from slack
Root cause
OldDot navigation on Android (PageNavigator) commits every page change synchronously with
commitNowAllowingStateLoss()(popLastPage, popAllPages, pushPage). When a navigation (e.g.popLastPagetriggered by a network response) runs while the previous page's exit animation is still in progress, AndroidX cancels that animation and destroys the page inside the running transaction. BaseViewController.onDestroy calls into JS, and the page's JSonDestroynavigates again synchronously: FixExpenseViolationsController.onDestroy -> endViolationFixingFlow -> NavigationManager.dismissModal. So a second commit starts while the first one is still executing ->IllegalStateException: FragmentManager is already executing transactions. The exception is thrown inside a JNI callback (yaplNavigationManager.handleCommand), so JSC aborts the app (SIGABRT). Sentry also shows the same nested pattern from YaplActivityBase.onResume ->yaplOpenNewApp->popAllPages.Solution
Make PageNavigator re-entrancy safe instead of patching each JS
onDestroy. It tracks when a fragment commit is in progress, and any navigation command (push/pop/dismiss) that arrives during that time is deferred to the next main-loop tick instead of being committed in a nested way. Normal navigation is unchanged; only the case that crashes today gets delayed by one tick. This covers both crash patterns in Sentry and any other page whoseonDestroy/lifecycle callback navigates.@MelvinBot validate this approach
MelvinBot commentedon Oct 15, 2026
Verdict: The approach is sound for the crash in the stack trace. Add a fallback, though, because a navigator-owned flag won't catch every nested commit.
I couldn't read the native code or Sentry from here, so I checked the plan against the public AndroidX source only.
What AndroidX confirms
commitNowAllowingStateLoss()holds the "executing" state for the whole commit (FragmentManager.java#L1978-L1997). The exception comes from that state (#L1924-L1927).onDestroythen runs inside the new commit (FragmentManager.java#L2201-L2206, DefaultSpecialEffectsController.kt#L601-L608). This matches your root cause.Gaps to cover
IllegalStateExceptionaround the commit and post the command as a fallback.To reproduce: Set Animator duration scale to 10x in Developer options. Then trigger the second navigation while the exit animation runs.
view run
ZhenjaHorbach commentedon Oct 15, 2026
This proposal looks good to me!
🎀👀🎀 С+
melvin-bot commentedon Oct 15, 2026
Current assignee @mountiny is eligible for the choreEngineerContributorManagement assigner, not assigning anyone new.