Skip to content

[go_router] pop() not working when both top-level 'onEnter' and 'redirect' are async and the route have onExit callback #180002

Description

@enzod-lgtm

What package does this bug report belong to?

go_router

What target platforms are you seeing this bug on?

Android, iOS

Have you already upgraded your packages?

Yes

Dependency versions

pubspec.lock
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
  characters:
    dependency: transitive
    description:
      name: characters
      sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
      url: "https://pub.dev"
    source: hosted
    version: "1.4.0"
  collection:
    dependency: transitive
    description:
      name: collection
      sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
      url: "https://pub.dev"
    source: hosted
    version: "1.19.1"
  flutter:
    dependency: "direct main"
    description: flutter
    source: sdk
    version: "0.0.0"
  flutter_web_plugins:
    dependency: transitive
    description: flutter
    source: sdk
    version: "0.0.0"
  go_router:
    dependency: "direct main"
    description:
      name: go_router
      sha256: eff94d2a6fc79fa8b811dde79c7549808c2346037ee107a1121b4a644c745f2a
      url: "https://pub.dev"
    source: hosted
    version: "17.0.1"
  logging:
    dependency: transitive
    description:
      name: logging
      sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
      url: "https://pub.dev"
    source: hosted
    version: "1.3.0"
  material_color_utilities:
    dependency: transitive
    description:
      name: material_color_utilities
      sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
      url: "https://pub.dev"
    source: hosted
    version: "0.11.1"
  meta:
    dependency: transitive
    description:
      name: meta
      sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
      url: "https://pub.dev"
    source: hosted
    version: "1.17.0"
  sky_engine:
    dependency: transitive
    description: flutter
    source: sdk
    version: "0.0.0"
  vector_math:
    dependency: transitive
    description:
      name: vector_math
      sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
      url: "https://pub.dev"
    source: hosted
    version: "2.2.0"
sdks:
  dart: ">=3.9.0 <4.0.0"
  flutter: ">=3.35.0"

Steps to reproduce

Using the provided code:

  1. tap "Go to Details" button ( context.push() )
  2. tap "Back" button ( context.pop() )
  3. page is not popped

Things to note:

  • both declared routes are at the same level
  • navigation is done via context.push() and context.pop(), not context.go()

Problem:

This problem appears only when both top-level onEnter and top-level redirect callbacks return a Future AND the route you try to pop has an onExit callback (async or sync).

In my example, the bug disappears if you either:

  • remove the onEnter
  • make onEnter synchronous
  • remove the redirect
  • make redirect synchronous
  • remove the onExit callback from the route being pop

Also keep in mind that go_router_builder systematically creates an onExit callback (that returns true) for the generated routes, even when no override is provided, which is different from the behavior of a "manual" GoRoute, because not giving an onExit callback to GoRoute the constructor will lead to onExit being null.

So this problem can pop when migrating to go_router_builder, because it will add a default onExit callbacks to GoRoute that previously had a null onExit.

Expected results

When tapping the "Back" button on the Details page, it should pop the current route and show the Home page

Actual results

When tapping the "Back" button on the Details page, the route is not popped and nothing happens.
If I tap again, an Exception is thrown. (see the stacktrace below)

Code sample

Code sample
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(_) {
    return MaterialApp.router(
      routerConfig: GoRouter(
        debugLogDiagnostics: true,
        onEnter: (_, __, ___, ____) => Future.value(const Allow()), // <=======
        redirect: (_, __) => Future.value(null), // <=======
        routes: <RouteBase>[
          GoRoute(
            path: '/',
            builder: (_, __) => const HomePage(),
          ),
          GoRoute(
            path: '/details',
            builder: (_, __) => const DetailsPage(),
            onExit: (_, __) => Future.value(true), // <=======
          ),
        ],
      ),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('Home page'),
            ElevatedButton(
              onPressed: () => context.push('/details'), // <=======
              child: const Text('Go to Details'),
            ),
          ],
        ),
      ),
    );
  }
}

class DetailsPage extends StatelessWidget {
  const DetailsPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('Details page'),
            ElevatedButton(
              onPressed: () => context.pop(), // <=======
              child: const Text('Back'),
            ),
          ],
        ),
      ),
    );
  }
}

Screenshots or Videos

Screenshots / Video demonstration

Not working:
https://github.com/user-attachments/assets/5f0c78e9-4547-4526-b7b2-58ada099c6e8

Working (no onEnter OR no redirect):
https://github.com/user-attachments/assets/9a03915b-30a0-4ae3-aac6-f614765eaaba

Logs

Logs

Launching the app and tapping "Go To Details" button:

[GoRouter] Full paths for routes:
           ├─/ (HomePage)
           └─/details (DetailsPage)
[GoRouter] setting initial location null
[GoRouter] Using MaterialApp configuration
[GoRouter] pushing /details

Pressing "Back" button on Details page (page is not popped):

[GoRouter] popping /
[GoRouter] restoring /

Pressing a second time the "Back" button:

[GoRouter] popping /
[GoRouter] restoring /
[ERROR:flutter/runtime/dart_vm_initializer.cc(40)] Unhandled Exception: Bad state: Future already completed
#0      _AsyncCompleter.complete (dart:async/future_impl.dart:97:31)
#1      ImperativeRouteMatch.complete (package:go_router/src/match.dart:489:15)
#2      GoRouterDelegate._completeRouteMatch (package:go_router/src/delegate.dart:187:14)
#3      GoRouterDelegate._handlePopPageWithRouteMatch.<anonymous closure> (package:go_router/src/delegate.dart:167:9)
<asynchronous suspension>

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.38.4, on macOS 26.2 25C56 darwin-arm64, locale en-FR) [7.4s]
    • Flutter version 3.38.4 on channel stable at /Users/REDACTED/fvm/versions/3.38.4
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 66dd93f9a2 (2 weeks ago), 2025-12-03 14:56:10 -0800
    • Engine revision a5cb96369e
    • Dart version 3.10.3
    • DevTools version 2.51.1
    • Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, cli-animations, enable-native-assets, omit-legacy-version-file, enable-lldb-debugging

[✓] Android toolchain - develop for Android devices (Android SDK version 36.1.0) [9.7s]
    • Android SDK at /Users/REDACTED/Library/Android/sdk
    • Emulator version 36.2.12.0 (build_id 14214601) (CL:N/A)
    • Platform android-36, build-tools 36.1.0
    • Java binary at: /Library/Java/JavaVirtualMachines/openjdk-17.jdk/Contents/Home/bin/java
      This JDK is specified in your Flutter configuration.
      To change the current JDK, run: `flutter config --jdk-dir="path/to/jdk"`.
    • Java version OpenJDK Runtime Environment Homebrew (build 17.0.13+0)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 26.2) [13.3s]
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 17C52
    • CocoaPods version 1.16.2

[✓] Chrome - develop for the web [11ms]
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Connected device (4 available) [8.6s]
    • iPhone 15 Pro (iOS 26.2) (mobile) • 8630355B-90A8-450F-A036-C213C21DC870 • ios            • com.apple.CoreSimulator.SimRuntime.iOS-26-2 (simulator)
    • iPhone 15 Pro (mobile)            • 3D789230-DF92-4EF7-89E6-1E9072D77DEA • ios            • com.apple.CoreSimulator.SimRuntime.iOS-26-1 (simulator)
    • macOS (desktop)                   • macos                                • darwin-arm64   • macOS 26.2 25C56 darwin-arm64
    • Chrome (web)                      • chrome                               • web-javascript • Google Chrome 140.0.7339.133

[✓] Network resources [281ms]
    • All expected network resources are available.

• No issues found!

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work listfound in release: 3.38Found to occur in 3.38found in release: 3.40Found to occur in 3.40has reproducible stepsThe issue has been confirmed reproducible and is ready to work onp: go_routerThe go_router packagepackageflutter/packages repository. See also p: labels.team-frameworkOwned by Framework teamtriaged-frameworkTriaged by Framework team

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions