Skip to content

[go_router] Fixes "Bad state: Future already completed" when a route with onExit is popped twice - #12500

Open
iCodePoet wants to merge 1 commit into
flutter:mainfrom
iCodePoet:fix/go-router-double-pop-completed-future
Open

[go_router] Fixes "Bad state: Future already completed" when a route with onExit is popped twice#12500
iCodePoet wants to merge 1 commit into
flutter:mainfrom
iCodePoet:fix/go-router-double-pop-completed-future

Conversation

@iCodePoet

Copy link
Copy Markdown

When a route with an onExit callback is popped, GoRouterDelegate._handlePopPageWithRouteMatch vetoes the synchronous pop (returns false) and defers completion to a scheduleMicrotask. Because the page is still on the navigator until the configuration change is applied, a second back event arriving in that window (e.g. a user tapping the back button twice in quick succession) reaches the delegate with the same RouteMatchBase and schedules a second microtask. Both microtasks call _completeRouteMatchImperativeRouteMatch.complete() on the same completer, and the second call throws an unhandled StateError: Bad state: Future already completed.

This affects far more apps than explicit onExit users: any app using go_router_builder typed routes generated before the hasOverriddenOnExit parameter existed gets an implicit onExit wired by GoRouteData.$route (it treats a null hasOverriddenOnExit as true for backward compatibility), so every typed route takes the deferred pop path. We hit this in production from users double-tapping the AppBar back button.

This PR makes ImperativeRouteMatch.complete() ignore completions after the first, so the first pop's result is reported and the redundant second pop becomes a no-op (RouteMatchList.remove already returns the list unchanged when the match is gone). A regression test reproducing the double-pop is included; it fails with a StateError without the fix.

Fixes flutter/flutter#191280

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

@google-cla

google-cla Bot commented Aug 18, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@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 updates the go_router package to version 17.5.1. It addresses a StateError by ensuring that ImperativeRouteMatch.complete returns early if its underlying completer is already completed, preventing multiple completions when a route is popped twice before the navigator rebuilds. A corresponding regression test has been added to on_exit_test.dart, and the CHANGELOG.md has been updated. There are no review comments, so no additional feedback is provided.

@github-actions github-actions Bot added p: go_router triage-framework Should be looked at in framework triage labels Aug 18, 2026
@iCodePoet
iCodePoet force-pushed the fix/go-router-double-pop-completed-future branch from 2cc1e89 to 7cecaf4 Compare August 18, 2026 17:41
@iCodePoet

Copy link
Copy Markdown
Author

@googlebot I signed it!

@iCodePoet
iCodePoet force-pushed the fix/go-router-double-pop-completed-future branch from 7cecaf4 to 5276a8a Compare August 18, 2026 17:50
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

Development

Successfully merging this pull request may close these issues.

[go_router] "Bad state: Future already completed" crash when a route with an onExit callback is popped twice quickly

1 participant