The Problem

A navigation guard redirects to another route, which triggers the guard again, creating an infinite loop. The browser eventually crashes with "Too many redirects" or the Vue Router aborts with an error.

Symptoms

  • Browser shows "ERR_TOO_MANY_REDIRECTS"
  • Console: "Redirected when going from /login to /dashboard via a navigation guard"
  • App hangs on a blank page
  • Navigation guard logs show the same routes cycling repeatedly

Real Error Scenario

```javascript router.beforeEach((to, from, next) => { const isAuthenticated = !!localStorage.getItem('token');

if (!isAuthenticated) { next('/login'); // Redirects to /login } else { next(); } }); ```

This creates an infinite loop: the user is not authenticated, so they redirect to /login. But /login also triggers the guard, which again checks authentication and redirects to /login again.

How to Fix It

Fix 1: Check if Already on Target Route

```javascript router.beforeEach((to, from, next) => { const isAuthenticated = !!localStorage.getItem('token');

if (!isAuthenticated && to.path !== '/login') { next('/login'); // Only redirect if not already on login } else { next(); } }); ```

Fix 2: Use Meta Flags for Route Protection

```javascript const routes = [ { path: '/login', component: Login, meta: { guest: true } }, { path: '/dashboard', component: Dashboard, meta: { requiresAuth: true } }, { path: '/', component: Home } ];

router.beforeEach((to, from, next) => { const isAuthenticated = !!localStorage.getItem('token');

if (to.meta.requiresAuth && !isAuthenticated) { next({ path: '/login', query: { redirect: to.fullPath } }); } else if (to.meta.guest && isAuthenticated) { next('/dashboard'); // Authenticated users should not see login } else { next(); } }); ```

Fix 3: Detect and Break the Loop

javascript
router.beforeEach((to, from, next) => {
  if (to.path === from.path) {
    next(false); // Break the loop
    return;
  }
  // ... normal guard logic
});

Fix 4: Handle Token Expiration Gracefully

```javascript router.beforeEach(async (to, from, next) => { const token = localStorage.getItem('token');

if (to.meta.requiresAuth) { if (!token) { next({ name: 'login', query: { redirect: to.fullPath } }); return; }

try { await store.dispatch('auth/verifyToken', token); next(); } catch { localStorage.removeItem('token'); next({ name: 'login', query: { redirect: to.fullPath } }); } } else { next(); } }); ```

Prevention

  • Always check to.path before redirecting
  • Use route meta flags instead of hardcoding paths
  • Add a redirect query parameter to return after login
  • Test guard logic with every route combination
  • Use Vue Router's built-in next(false) to cancel navigation when needed