Skip to content

[go_router] Fix popRoute crash when a shell route's navigator is not mounted#12111

Open
brotoo25 wants to merge 3 commits into
flutter:mainfrom
brotoo25:go-router-poproute-unmounted-shell-guard
Open

[go_router] Fix popRoute crash when a shell route's navigator is not mounted#12111
brotoo25 wants to merge 3 commits into
flutter:mainfrom
brotoo25:go-router-poproute-unmounted-shell-guard

Conversation

@brotoo25

@brotoo25 brotoo25 commented Jul 6, 2026

Copy link
Copy Markdown

GoRouterDelegate._findCurrentNavigators() force-unwraps each shell navigator's state (walker.navigatorKey.currentState!) while walking the current configuration. When the system back button is pressed while currentConfiguration references a ShellRoute whose navigator is not mounted — a transient state during redirects away from a shell or when resuming from background — popRoute() throws Null check operator used on a null value and crashes the app (observed in production via crash reporting on go_router 17.3.0, Android).

This applies the same null-tolerant handling that canPop() in the same file already uses for this state: if a shell navigator along the chain is not mounted, stop walking — nothing below it can be mounted either. This mirrors the existing early-break for pageless routes in the same loop, and the root navigator in this method is already null-guarded in the same way.

The added regression test pins the transient state deterministically (configuration pointing at a shell route while the widget tree shows a non-shell route) and fails on main with the exact production stack trace before this change.

Related to, but distinct from, flutter/flutter#187616 and #11911: those cover currentConfiguration.matches being empty (Bad state: No element); this PR fixes the non-empty case where a shell navigator is unmounted. The two changes are independent and compatible.

Fixes flutter/flutter#188993

Pre-Review Checklist

Footnotes

  1. Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. 2

…mounted

GoRouterDelegate._findCurrentNavigators force-unwraps each shell
navigator's state while walking the current configuration. When the
system back button is pressed while the configuration references a
shell route whose navigator is not mounted (e.g. mid-redirect away
from the shell, or while resuming from background), popRoute throws
'Null check operator used on a null value'.

Stop walking when a shell navigator is not mounted, matching the
null-tolerant handling canPop already uses for the same state.

Fixes flutter/flutter#188993
@github-actions github-actions Bot added p: go_router triage-framework Should be looked at in framework triage labels Jul 6, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request addresses a potential crash in popRoute() within GoRouterDelegate when a shell route's navigator is not mounted. The implementation replaces a force-unwrap operator with a null check, breaking the traversal loop if the navigator state is null. A widget test simulating this scenario has been added to prevent regressions, and a pending changelog entry has been created. There are no review comments, and I have no feedback to provide.

@Piinks Piinks requested review from chunhtai and hannah-hyj July 7, 2026 22:02
while (walker is ShellRouteMatch) {
final NavigatorState potentialCandidate = walker.navigatorKey.currentState!;
final NavigatorState? potentialCandidate = walker.navigatorKey.currentState;
if (potentialCandidate == null) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

looking at the issue, do you have a reproducible code that show case the transient state?

also I am not too sure what may be the correct behavior when the backbutton is pressed during that state. It felt wrong to pop the parent navigator because child navigator is in transient state. Perhaps the correct solution will be disallow the current configuration to be in such state

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

p: go_router triage-framework Should be looked at in framework triage

Projects

None yet

2 participants