[go_router] Assertion failure in setNewRoutePath when onException fires on the initial navigation
- Dominant language
- Dart
- Stars
- 179k
- Forks
- 31.1k
- PR merge metrics
- PR metrics pending
Description
### What package does this bug report belong to?
go_router
### What target platforms are you seeing this bug on?
Android, iOS, Web, macOS, Linux, Windows
### Have you already upgraded your packages?
Yes
### Dependency versions
pubspec.lock
```lock
go_router 17.3.0
(also reproduced against packages/go_router at flutter/packages main, 9e58c600b0)
```
### Steps to reproduce
1. Create a `GoRouter` with an `onEnter` callback that returns `Block.stop()` for the initial location, and provide an `onException` handler.
2. Start the app (any platform — this is pure routing logic; we originally hit it with deep links on web).
The crash happens during `setInitialRoutePath`, so the app crashes on startup.
### Expected results
No crash. `onException` runs and the app can recover (show an error state or navigate elsewhere).
### Actual results
Assertion failure in `GoRouterDelegate.setNewRoutePath`:
```
'package:go_router/src/delegate.dart': Failed assertion: line 221 pos 12:
'configuration.isNotEmpty || configuration.isError': is not true.
```
Cause: when `onException` is provided, the `parserExceptionHandler` closure in `router.dart` always returns `routerDelegate.currentConfiguration`. On the initial navigation nothing has committed yet, so that configuration is empty (`isNotEmpty == false`, `isError == false`) and the delegate assertion fires. The fix (flutter/packages#12216) has two parts. `router.dart` falls back to the error match list when the current configuration isn't valid yet — the error list has `isError == true`, so the assertion is satisfied. We've been running this half in a fork in production. And `parser.dart` defers the `onException` invocation past the in-flight initial parse for the blocked-with-no-prior-route case: without that, a recovery navigation made synchronously inside `onException` (like the `router.go('/fallback')` above) is silently discarded by the `Router`'s intent-token churn, and the app stays parked on the error state instead of recovering.
### Code sample
Code sample
```dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
void main() => runApp(App());
class App extends StatelessWidget {
App({super.key});
late final GoRouter router = GoRouter(
initialLocation: '/protected',
onEnter: (_, __, next, ___) =>
next.matchedLocation == '/protected' ? const Block.stop() : const Allow(),
onException: (context, state, router) => router.go('/fallback'),
routes: [
GoRoute(path: '/protected', builder: (_, __) => const SizedBox()),
GoRoute(path: '/fallback', builder: (_, __) => const SizedBox()),
],
);
@override
Widget build(BuildContext context) => MaterialApp.router(routerConfig: router);
}
```
### Screenshots or Videos
Screenshots / Video demonstration
N/A (startup crash).
### Logs
Logs
```console
'package:go_router/src/delegate.dart': Failed assertion: line 221 pos 12:
'configuration.isNotEmpty || configuration.isError': is not true.
#2 GoRouterDelegate.setNewRoutePath (package:go_router/src/delegate.dart:221:12)
#3 RouterDelegate.setInitialRoutePath (package:flutter/src/widgets/router.dart:1358:12)
```
### Flutter Doctor output
Doctor output
```console
[✓] Flutter (Channel stable, 3.44.4, on macOS 26.5.2 25F84 darwin-arm64, locale en-US) [609ms]
• Flutter version 3.44.4 on channel stable at ~/repos/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision ad70ec4617 (3 weeks ago), 2026-06-24 11:07:06 -0700
• Engine revision a10d8ac38d
• Dart version 3.12.2
• DevTools version 2.57.0
• Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, cli-animations, enable-native-assets, enable-swift-package-manager, omit-legacy-version-file, enable-lldb-debugging, enable-uiscene-migration
[✓] Android toolchain - develop for Android devices (Android SDK version 36.0.0) [1,824ms]
• Android SDK at ~/Library/Android/sdk
• Emulator version unknown
• Platform android-36, build-tools 36.0.0
• ANDROID_HOME = ~/Library/Android/sdk
• Java binary at: ~/Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
This is the JDK bundled with the latest Android Studio installation on this machine.
To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`.
• Java version OpenJDK Runtime Environment (build 21.0.6+-13391695-b895.109)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 26.6) [1,335ms]
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 17F113
• CocoaPods version 1.16.2
[✓] Chrome - develop for the web [6ms]
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Connected device (2 available) [6.8s]
• macOS (desktop) • macos • darwin-arm64 • macOS 26.5.2 25F84 darwin-arm64
• Chrome (web) • chrome • web-javascript • Google Chrome 150.0.7871.116
[✓] Network resources [789ms]
• All expected network resources are available.
• No issues found!
```
Contributor guide
Research direction
Start with packages/go_router/lib/src/router.dart and parser.dart, then inspect the assertion in packages/go_router/lib/src/delegate.dart. Run the supplied initial blocked-navigation reproduction and review flutter/packages#12216. Done means initial navigation no longer asserts and synchronous recovery from onException reaches the fallback route.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- dart
- Domain
- desktop-dev, mobile-dev, web-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 25/100