Description:
When a RouteGuard blocks navigation and redirects via redirectTo, the redirect is resolved internally by selectBook() through _routeSuccess(), which replaces the RedirectRoute with the actual target route before returning the ModularBook. By the time pushNamed receives this book, it has no way to know a redirect occurred.
The pushNamed logic then tries to add the resolved route to the current stack. If that route already exists (e.g., the user is already on /login/ and tries to access a guarded route), the deduplication loop skips it — but the fallback on the next line unconditionally forces it in anyway:
// modular_router_delegate.dart
if (currentConfiguration!.routes.length == list.length) {
list.add(book.routes.last); // ← forces duplicate
}
This results in a stack like [/login/, /login/], which causes a spurious back button to appear on the home screen AppBar.
Steps to Reproduce:
- Create an app with
flutter_modular and define a guarded route:
ModuleRoute('/admin/', module: AdminModule(), guards: [AuthGuard()])
- Implement the guard with
redirectTo:
class AuthGuard extends RouteGuard {
AuthGuard() : super(redirectTo: '/login/');
@override
Future<bool> canActivate(String path, ModularRoute route) async {
return Modular.get<AuthController>().isLoggedIn;
}
}
- While already on
/login/, trigger:
Modular.to.pushNamed('/admin/dashboard');
(This happens naturally via push notification deep links or any external navigation attempt.)
Observe the AppBar on /distributor/home/ now has a back arrow pointing to an identical /distributor/home/ page.
Expected behavior
When a RouteGuard redirects to a route that already exists in the navigation stack, the stack should remain clean — no duplicate entries, no spurious back button.
Actual Behavior:
The redirected route is duplicated in the stack ([/login/, /login/]), causing a back button to appear on the home screen. Pressing it navigates to an identical copy of the same page.
Root Cause:
In modular_router_delegate.dart, pushNamed cannot distinguish between:
- A redirect that resolved to an existing route (should replace the stack)
- An intentional push of the same route with different arguments (should stack)
The fallback list.add(book.routes.last) was designed for the second case but incorrectly fires in the first.
Suggested Fix:
Detect whether the resolved route differs from the originally requested one. If it does, a guard redirect occurred and setNewRoutePath should be used instead of accumulating:
Future<T?> pushNamed<T extends Object?>(String routeName, ...) async {
// ...
final requestedPath = Uri.parse(routeName).path.replaceAll(RegExp(r'/$'), '');
final resolvedPath = book.routes.last.uri.path.replaceAll(RegExp(r'/$'), '');
final wasRedirected = requestedPath != resolvedPath;
if (wasRedirected) {
await setNewRoutePath(book);
return await popComplete.future;
}
// existing push logic with deduplication loop + fallback...
}
Environment:
flutter_modular: 6.3.4
Flutter: 3.35.4
Note:
I would like to work on a fix for this issue. I'm available to submit a PR with the suggested approach above, or an alternative if the maintainers prefer a different solution.
Description:
When a RouteGuard blocks navigation and redirects via redirectTo, the redirect is resolved internally by selectBook() through _routeSuccess(), which replaces the RedirectRoute with the actual target route before returning the ModularBook. By the time pushNamed receives this book, it has no way to know a redirect occurred.
The pushNamed logic then tries to add the resolved route to the current stack. If that route already exists (e.g., the user is already on
/login/and tries to access a guarded route), the deduplication loop skips it — but the fallback on the next line unconditionally forces it in anyway:This results in a stack like
[/login/, /login/], which causes a spurious back button to appear on the home screen AppBar.Steps to Reproduce:
flutter_modularand define a guarded route:redirectTo:/login/, trigger:(This happens naturally via push notification deep links or any external navigation attempt.)
Observe the AppBar on /distributor/home/ now has a back arrow pointing to an identical /distributor/home/ page.
Expected behavior
When a
RouteGuardredirects to a route that already exists in the navigation stack, the stack should remain clean — no duplicate entries, no spurious back button.Actual Behavior:
The redirected route is duplicated in the stack (
[/login/, /login/]), causing a back button to appear on the home screen. Pressing it navigates to an identical copy of the same page.Root Cause:
In
modular_router_delegate.dart, pushNamed cannot distinguish between:The fallback list.add(book.routes.last) was designed for the second case but incorrectly fires in the first.
Suggested Fix:
Detect whether the resolved route differs from the originally requested one. If it does, a guard redirect occurred and setNewRoutePath should be used instead of accumulating:
Environment:
flutter_modular: 6.3.4Flutter: 3.35.4Note:
I would like to work on a fix for this issue. I'm available to submit a PR with the suggested approach above, or an alternative if the maintainers prefer a different solution.