[go_router] Fix chained top-level redirects not being fully resolved (#11108) Fixes https://github.com/flutter/flutter/issues/178984 The `onEnter` refactor (commit `9ec29b6d23`, PR #8339) split the unified `redirect()` method into `applyTopLegacyRedirect()` (top-level, runs once) and `redirect()` (route-level only). This introduced two regressions: 1. **Top-level redirect chains broken**: `applyTopLegacyRedirect()` returned after one hop — a chain like `/ → /a → /b` stopped at `/a` instead of resolving to `/b`. 2. **Route-level → top-level chains broken**: `processRouteLevelRedirect()` recursed into `redirect()` without re-evaluating the top-level redirect on the new location. ### Fix Unify top-level and route-level redirects back into `redirect()` as the single entry point for all redirect processing, while keeping the separation of concerns via `applyTopLegacyRedirect()` as an internal helper. > **Note:** An earlier revision of this PR (v1) kept the split but added recursive calls in both methods. Based on [reviewer feedback](https://github.com/flutter/packages/pull/11108#discussion_r2943354003), the approach was refactored to move `applyTopLegacyRedirect()` inside `redirect()` so the caller (`parseRouteInformationWithDependencies`) doesn't need to know about the two-phase process. #### Before (broken) ```mermaid sequenceDiagram participant Parser as parseRouteInformationWithDependencies participant TopRedir as applyTopLegacyRedirect participant Redir as redirect (route-level only) Parser->>TopRedir: / (one hop only) TopRedir-->>Parser: /a (stops here ✗) Parser->>Redir: /a Redir->>Redir: route-level redirects Note right of Redir: No top-level re-evaluation Redir-->>Parser: result ``` #### After (fix) ```mermaid sequenceDiagram participant Parser as parseRouteInformationWithDependencies participant Redir as redirect (unified) participant TopRedir as applyTopLegacyRedirect Parser->>Redir: / (initial matches) Redir->>TopRedir: / → top-level redirect chain TopRedir->>TopRedir: / → /a → /b (self-recursive) TopRedir-->>Redir: /b (fully resolved ✓) Redir->>Redir: route-level redirects on /b Note right of Redir: If route-level changes location,<br/>recurse → top-level re-evaluated Redir-->>Parser: final result ``` #### Key changes - **`configuration.dart` — `redirect()`**: Now calls `applyTopLegacyRedirect()` first at every cycle, then processes route-level redirects on the post-top-level result. Route-level `_processRouteLevelRedirects` extracted as a helper. - **`configuration.dart` — `applyTopLegacyRedirect()`**: Self-recursive to fully resolve top-level chains. No functional change from v1. - **`parser.dart` — `parseRouteInformationWithDependencies()`**: Simplified — no longer calls `applyTopLegacyRedirect` separately. Just passes initial matches to `_navigate()`. - **`parser.dart` — `_navigate()`**: Removed `preSharedHistory` parameter. Added `context.mounted` guard in the result `.then()` to protect the relocated async boundary. Both fixes share the existing `redirectHistory` for loop detection and respect `redirectLimit`. The `onEnter` system is completely unaffected — it runs before redirects in the pipeline. ### Tests - **19 redirect chain tests** (`redirect_chain_test.dart`): top-level chains, async chains, loop detection (including loop-to-initial), route→top cross-type chains, **async cross-type chains** (async top→route, async route→sync top, sync route→async top), **context disposal** during async top-level and route-level redirects, redirect limit boundary (exact limit succeeds, limit+1 fails), shared limit across redirect types. - **3 onEnter interaction tests** (`on_enter_test.dart`): onEnter called once when chains resolve, onEnter block prevents redirect evaluation. - **Full suite**: 418 tests pass, 0 regressions. ## Pre-Review Checklist [^1]: This PR uses `pending_changelogs/` for versioning and changelog, following the go_router batch release process.
This repo is a companion repo to the main flutter repo. It contains the source code for Flutter's first-party packages (i.e., packages developed by the core Flutter team). Check the packages directory to see all packages.
These packages are also available on pub.
Please file any issues, bugs, or feature requests in the main flutter repo. Issues pertaining to this repository are labeled “package”.
If you wish to contribute a new package to the Flutter ecosystem, please see the documentation for developing packages. You can store your package source code in any GitHub repository (the present repo is only intended for packages developed by the core Flutter team). Once your package is ready you can publish to the pub repository.
If you wish to contribute a change to any of the existing packages in this repo, please review our contribution guide, and send a pull request.
These are the packages hosted in this repository: