Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[go_router] Fix Block.then() re-entrancy when triggered by refreshListenable#11136

Open
davidmigloz wants to merge 1 commit intoflutter:mainfrom
davidmigloz:fix/block-then-reentrance
Open

[go_router] Fix Block.then() re-entrancy when triggered by refreshListenable#11136
davidmigloz wants to merge 1 commit intoflutter:mainfrom
davidmigloz:fix/block-then-reentrance

Conversation

@davidmigloz
Copy link
Contributor

@davidmigloz davidmigloz commented Feb 27, 2026

Fixes flutter/flutter#183012

Block.then(() => router.go(...)) and Allow(then: () => router.go(...)) callbacks in onEnter silently lose their navigation when triggered by refreshListenable. The router.go() inside the callback runs synchronously during handleTopOnEnter processing, triggering a re-entrant _processRouteInformation whose result is dropped due to transaction token churn in Flutter's Router.

Reproduction repo: https://github.com/davidmigloz/flutter_block_then_bug
Live demo: https://davidmigloz.github.io/flutter_block_then_bug/

Root Cause

In parser.dart, handleTopOnEnter executes the then callback via await Future<void>.sync(callback) (line 533). When the callback calls router.go('/login'), it synchronously triggers notifyListeners()_processRouteInformation while the outer parse is still in-flight. Flutter's Router mints a new transaction token for the re-entrant parse and silently discards the result.

Fix

Replace await Future<void>.sync(callback) with scheduleMicrotask(() async { await callback(); }). This defers the callback to the microtask queue, ensuring router.go() runs after the current parse has completed and Flutter's Router has committed the result.

This is the minimal deferral (before any timer/frame), and the behavior change (callbacks fire asynchronously instead of synchronously) is consistent with the documentation ("Executed after the decision is committed").

Tests

  • 5 regression tests (on_enter_test.dart): Block.then(router.go) + refreshListenable, Block.then(router.goNamed) variant, rapid refreshListenable emissions, Allow.then(router.go) variant, error propagation after deferral.
  • Full suite: 395 tests pass, 0 regressions (2 skipped, pre-existing).

Pre-Review Checklist

Footnotes

  1. This PR uses pending_changelogs/ for versioning and changelog, following the go_router batch release process. 2 3

…tenable

`Block.then(() => router.go(...))` callbacks silently lose their
navigation when triggered by `refreshListenable`. The `router.go()`
inside the callback runs synchronously during `handleTopOnEnter`,
triggering a re-entrant `_processRouteInformation` whose result is
dropped due to transaction token churn in Flutter's Router.

Fix: wrap the `then` callback in `scheduleMicrotask()` so it runs
after the current parse completes and Flutter's Router has committed
the result. This is consistent with the `then` documentation which
states the callback is "executed after the decision is committed".

Adds 5 regression tests covering Block.then + refreshListenable,
goNamed variant, rapid emissions, Allow.then, and error propagation.

Fixes flutter/flutter#183012
@github-actions github-actions bot added p: go_router triage-framework Should be looked at in framework triage labels Feb 27, 2026
Copy link

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

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 re-entrancy issue in go_router where navigations within Block.then() and Allow.then() callbacks, triggered by refreshListenable, were being lost. The fix defers the execution of these callbacks using scheduleMicrotask, ensuring they run after the current route parsing is complete, thus preventing the re-entrancy problem. The change is accompanied by a comprehensive suite of new regression tests covering various scenarios, including router.go, router.goNamed, rapid refreshListenable events, and error propagation. A corresponding changelog entry has also been added.

Copy link
Contributor

@chunhtai chunhtai left a comment

Choose a reason for hiding this comment

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

LGTM

@chunhtai chunhtai requested a review from hannah-hyj February 27, 2026 18:34
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] Block.then(() => router.go(...)) navigation silently lost when triggered by refreshListenable

2 participants