Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions packages/go_router/lib/src/misc/errors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,14 @@ class GoException implements Exception {
@override
String toString() => 'GoException: $message';
}

/// Raised when `Block` is returned from `onEnter` but there is no prior
/// route configuration to restore (e.g., an initial deep link was blocked).
///
/// Apps can check for this specific type in `onException` to recover
/// gracefully (e.g., redirect to a loading screen with the deep link
/// preserved) instead of treating it as a generic routing error.
class BlockedInitialNavigationException extends GoException {
/// Creates an exception for a blocked initial navigation attempt.
BlockedInitialNavigationException(super.message);
}
2 changes: 1 addition & 1 deletion packages/go_router/lib/src/parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ class GoRouteInformationParser extends RouteInformationParser<RouteMatchList> {
// Surface an error so the app decides how to recover via onException.
final RouteMatchList blocked = _OnEnterHandler._errorRouteMatchList(
effectiveRoute.uri,
GoException(
BlockedInitialNavigationException(
'Navigation to ${effectiveRoute.uri} was blocked by onEnter with no prior route to restore',
),
extra: infoState.extra,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
changelog: |
- Adds `BlockedInitialNavigationException` (a `GoException` subtype), raised when the initial navigation is blocked by `onEnter` with no prior route to restore, so apps can distinguish this case in `onException` without string matching.
version: minor
31 changes: 31 additions & 0 deletions packages/go_router/test/on_enter_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,37 @@ void main() {
expect(find.text('Fallback Page'), findsOneWidget);
});

testWidgets('Should raise BlockedInitialNavigationException when the initial navigation '
'is blocked by onEnter with no prior route to restore', (WidgetTester tester) async {
Object? capturedError;

router = GoRouter(
initialLocation: '/protected',
onEnter:
(
BuildContext context,
GoRouterState current,
GoRouterState next,
GoRouter goRouter,
) async {
if (next.uri.path == '/protected') {
return const Block.stop();
}
return const Allow();
},
onException: (BuildContext context, GoRouterState state, GoRouter goRouter) {
capturedError = state.error;
},
routes: <GoRoute>[GoRoute(path: '/protected', builder: (_, _) => const Placeholder())],
);

await tester.pumpWidget(MaterialApp.router(routerConfig: router));
await tester.pumpAndSettle();

expect(capturedError, isA<BlockedInitialNavigationException>());
expect(capturedError, isA<GoException>());
});

testWidgets('onEnter has priority over deprecated redirect', (WidgetTester tester) async {
var redirectCallCount = 0;
var onEnterCallCount = 0;
Expand Down