Home > Mobile >  (EXCEPTION CAUGHT BY GOROUTER) Failed assertion: line 299 pos 13: '!redirects.contains(redir)&#
(EXCEPTION CAUGHT BY GOROUTER) Failed assertion: line 299 pos 13: '!redirects.contains(redir)&#

Time:05-24

I am trying to use GoRoute, Stream, and Bloc. So, I am implementing Auth Process. So, if the user is not log-in they can't access any page. And, `Stream allows to constantly listen to AuthStatus (Bloc State). But, so how I am not sure, why but I am getting this error

Exception: 'package:go_router/src/go_router_delegate.dart':
Failed assertion: line 299 pos 13: '!redirects.contains(redir)':
redirect loop detected:

I tried to create a dummy app to understand what is exactly going wrong. But, I wasn't able to fig-out what is the reason. Just below I am attaching the code it's just ~200 lines anyone can copy and paste it and then run the command flutter run and an app error appears in the screen.

import 'dart:async';

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

enum Pages {
  home,
  profile,
  settings,
}

class FooStream {
  final StreamController<Pages> _controller;
  FooStream() : _controller = StreamController.broadcast();

  Stream<Pages> get stream {
    final listOfPages = [Pages.home, Pages.profile, Pages.settings];
    //  every 3 seconds loop over enum and emit a new value to the stream

    Timer.periodic(const Duration(seconds: 3), (timer) {
      final index = timer.tick ~/ 3;
      if (index >= listOfPages.length) {
        timer.cancel();
      } else {
        _controller.add(listOfPages[index]);
      }
    });

    return _controller.stream;
  }

  void update(Pages page) {
    _controller.add(page);
  }

  void close() {
    _controller.close();
  }

  void dispose() {
    _controller.close();
  }
}

class FooNotifier extends ChangeNotifier {
  final ValueNotifier<Pages> _page = ValueNotifier(Pages.home);

  ValueNotifier<Pages> get page => _page;

  // listen to the stream and whenever it emits a new value, update the page
  final FooStream stream;
  FooNotifier(this.stream) {
    stream.stream.listen((Pages page) {
      _page.value = page;
      notifyListeners();
    });
  }

  void close() {
    notifyListeners();
  }

  @override
  void dispose() {
    notifyListeners();
    super.dispose();
  }
}

// my home page
class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
          child: Text(
        "Home",
        style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
      )),
    );
  }
}

// profile page
class ProfilePage extends StatelessWidget {
  const ProfilePage({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
          child: Text(
        "Profile",
        style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
      )),
    );
  }
}

// setting page
class SettingPage extends StatelessWidget {
  const SettingPage({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
          child: Text(
        "Setting",
        style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
      )),
    );
  }
}

class FooRoute {
  final FooNotifier notifier;
  FooRoute(this.notifier);
  GoRouter routeTo() {
    return GoRouter(
      routes: [
        GoRoute(
          path: '/',
          builder: (context, state) => const MyHomePage(),
        ),
        GoRoute(
          path: '/profile',
          builder: (context, state) => const ProfilePage(),
        ),
        GoRoute(
          path: '/setting',
          builder: (context, state) => const SettingPage(),
        ),
      ],
      refreshListenable: notifier,
      redirect: safePage,
      debugLogDiagnostics: true,
    );
  }

  // on page change, return the new page
  String? safePage(GoRouterState state) {
    final newPage = notifier.page.value;

    // if the new page is the same as the current page, do nothing
    if (newPage == Pages.home) {
      return '/';
    }

    if (newPage == Pages.profile) {
      return '/profile';
    }

    if (newPage == Pages.settings) {
      return '/settings';
    }

    return null;
  }
}

class FooApp extends StatelessWidget {
  FooApp({
    Key? key,
  }) : super(key: key);

  final _router = FooRoute(FooNotifier(FooStream())).routeTo();

  // base the

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<Pages>(
      valueListenable: FooNotifier(FooStream()).page,
      builder: (context, value, child) {
        return MaterialApp.router(
          routerDelegate: _router.routerDelegate,
          routeInformationParser: _router.routeInformationParser,
        );
      },
    );
  }
}

void main(List<String> args) {
  runApp(FooApp());
}

I am also attaching the message which I get in the terminal. Once the above code runs.

Launching lib\main.dart on Windows in debug mode...
package:bug_test/main.dart:1
Connecting to VM Service at ws://127.0.0.1:63905/cNY-SYgW7KE=/ws
[GoRouter] known full paths for routes:
[GoRouter]   => /
[GoRouter]   => /profile
[GoRouter]   => /setting
[GoRouter] setting initial location /
flutter: ══╡ EXCEPTION CAUGHT BY GOROUTER ╞══════════════════════════════════════════════════════════════════
flutter: The following _Exception was thrown Exception during GoRouter navigation:
flutter: Exception: 'package:go_router/src/go_router_delegate.dart': Failed assertion: line 299 pos 13:
package:go_router/src/go_router_delegate.dart:299
flutter: '!redirects.contains(redir)': redirect loop detected: / => /
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #2      GoRouterDelegate._getLocRouteMatchesWithRedirects.redirected
package:go_router/src/go_router_delegate.dart:299
flutter: #3      GoRouterDelegate._getLocRouteMatchesWithRedirects
package:go_router/src/go_router_delegate.dart:322
flutter: #4      GoRouterDelegate._go
package:go_router/src/go_router_delegate.dart:245
flutter: #5      new GoRouterDelegate
package:go_router/src/go_router_delegate.dart:58
flutter: #6      new GoRouter
package:go_router/src/go_router.dart:46
flutter: #7      FooRoute.routeTo
package:bug_test/main.dart:122
flutter: #8      new FooApp
package:bug_test/main.dart:169
flutter: #9      main
flutter: #10     _runMain.<anonymous closure> (dart:ui/hooks.dart:132:23)
flutter: #11     _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:297:19)
flutter: (elided 3 frames from class _AssertionError and class _RawReceivePortImpl)
flutter: ════════════════════════════════════════════════════════════════════════════════════════════════════
flutter: Another exception was thrown: Exception: 'package:go_router/src/go_router_delegate.dart': Failed assertion: line 299 pos 13: '!redirects.contains(redir)': redirect loop detected: / => /
package:go_router/src/go_router_delegate.dart:299
[GoRouter] MaterialApp found
[GoRouter] refreshing /
2
flutter: Another exception was thrown: Exception: 'package:go_router/src/go_router_delegate.dart': Failed assertion: line 299 pos 13: '!redirects.contains(redir)': redirect loop detected: / => /
package:go_router/src/go_router_delegate.dart:299
[GoRouter] refreshing /
flutter: Another exception was thrown: Exception: 'package:go_router/src/go_router_delegate.dart': Failed assertion: line 299 pos 13: '!redirects.contains(redir)': redirect loop detected: / => /profile => /profile
package:go_router/src/go_router_delegate.dart:299
[GoRouter] refreshing /
[GoRouter] redirecting to /profile
flutter: Another exception was thrown: Exception: 'package:go_router/src/go_router_delegate.dart': Failed assertion: line 299 pos 13: '!redirects.contains(redir)': redirect loop detected: / => /profile => /profile
package:go_router/src/go_router_delegate.dart:299
[GoRouter] refreshing /
flutter: Another exception was thrown: Exception: 'package:go_router/src/go_router_delegate.dart': Failed assertion: line 299 pos 13: '!redirects.contains(redir)': redirect loop detected: / => /settings => /settings
package:go_router/src/go_router_delegate.dart:299
[GoRouter] refreshing /
[GoRouter] redirecting to /settings
Application finished.
Exited (sigterm)

I would be really grateful if someone can help me. Thank you

CodePudding user response:

I think you misunderstood the redirect parameter of GoRouter.
This attribute is listening to every changement of route, and was made to ease the redirect on certain circonstances (for example, the user is disconnected, so you redirect him toward the /login page).

The official documentation explains it very well.

Removing this parameter fixes your problem.

GoRouter routeTo() {
    return GoRouter(
      routes: [
        GoRoute(
          path: '/',
          builder: (context, state) => const MyHomePage(),
        ),
        GoRoute(
          path: '/profile',
          builder: (context, state) => const ProfilePage(),
        ),
        GoRoute(
          path: '/setting',
          builder: (context, state) => const SettingPage(),
        ),
      ],
      refreshListenable: notifier,
      debugLogDiagnostics: true,
    );
  }

and instead of using this method to create your navigation, your should use GoRouter.of(context).go('/profile') as explained here

  • Related