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
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.pathbefore 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