Why is vue-router giving me this error? To be clear, the login flow works as intended but I want to a) get rid of the errro and b) understand why the error is happening.
Error:
Uncaught (in promise) Error: Redirected from "/login" to "/" via a navigation guard.
Login flow
Login action:
doLogin({ commit }, loginData) {
commit("loginStart");
axiosClient
.post("/jwt-auth/v1/token", {
username: loginData.username,
password: loginData.password,
})
.then((response) => {
commit("loginStop", null);
commit("setUserData", response.data);
this.categories = airtableQuery.getTable("Categories");
commit("setCategories", this.categories);
this.locations = airtableQuery.getTable("Locations");
commit("setLocations", this.locations);
router.push("/"); // push to site root after authentication
})
.catch((error) => {
console.log(error.response.data.message);
commit("loginStop", error.response.data.message);
commit("delUserData");
});
},
Router:
const routes = [
{
path: "/login",
name: "Login",
component: Login,
meta: { requiresAuth: false },
},
{
path: "/",
name: "Home",
component: Home,
meta: { requiresAuth: true },
},
];
let entryUrl = null;
router.beforeEach((to, from, next) => {
let localStorageUserData = JSON.parse(localStorage.getItem("userData"));
let storeUserData = state.getters.getUserData;
let userData = localStorageUserData || storeUserData;
let isAuthenticated = userData.token !== "" && userData.token !== undefined;
if (to.matched.some((record) => record.meta.requiresAuth)) {
if (!isAuthenticated) {
if (to.name !== "Login" && to.name !== "Home") {
entryUrl = to.fullPath;
}
next({ name: "Login" });
} else if (entryUrl) {
let url = entryUrl;
entryUrl = null;
next(url);
} else {
next();
}
} else {
next();
}
});
I spent hours debugging this and got to the following results for the ugly Uncaught (in promise) Error: Redirected when going from ...
Error.
Note that the error is not for the "redirect". It's for the initial caller of the first navigation. Keep reading...
Read this comment.
TL;DR: Let's say you are on page A, and click on a button to take you to page B (kinda like method: goToB() { router.push('/B'); }
on page A). But there is a Navigation Guard for page B, that sends you to page C.
This error is a way for letting that goToB()
function know that the router hasn't been able to fulfill the desired task, and the user hasn't landed on /B
.
The biggest confusion here is that the redirect (landing on Page C) is, both:
goToB
in page A (i.e. router.push
), who expects the router to go to page B.That's why when it's popped as Error
, it's confusing and frustrating to "you", who looks at the system entirely and thinks nothing is wrong or erroneous!
router-link
if you canI ran into a case that <router-link>
was working fine, but router.push
was complaining. (I think router-link internally suppresses such errors.)
router.push
callThe router.push
function is returning a Promise
(as it can be considered, or will be, an asynchronous job). All you need to do is to suppress any Error it might throw via
router.push('/B').catch(() => {});
// Add this: ^^^^^^^^^^^^^^^^
If you think you have multiple instances of this, you can augment the push
function on the prototype
of the Router
via the snippet on the same comment to apply this to all the router.push
calls on the entire app.
The good news is it's giving you granularity level to choose which error you want to suppress (e.g. only NavigationFailureTypes.redirected
ones, for example. The enum is here)
If you are on TypeScript, be my guest on the conversion and typing https://gist.github.com/eyedean/ce6ab6a5108a1bd19ace64382144b5b0 :)
vue-router
! Your case might be solved by the time you read this. (As they have a plan to do so, apparently.)The error message is getting updated in the next version of vue-router. The error will read:
Redirected when going from "/login" to "/" via a navigation guard
Somewhere in your code, after being redirected to "/login", you are redirecting back to "/". And vue-router is complaining about. You'll want to make sure you only have one redirect per navigation action.
I had a similar error, but for an onboarding redirect in .beforeEach, which was resolved by replacing in the .beforeEach conditional logic:
next({ name: "Onboarding" });
with
router.push({ path: 'Onboarding' });
This error is meant to inform the caller of $router.push
that the navigation didn't go to where it was initially intended. If you expect a redirection you can safely ignore the error with the following code.
import VueRouter from 'vue-router'
const { isNavigationFailure, NavigationFailureType } = VueRouter
...
this.$router.push('/')
.catch((e) => {
if (!isNavigationFailure(e, NavigationFailureType.redirected)) {
Promise.reject(e)
}
}
See https://github.com/vuejs/vue-router/issues/2932 for a discussion regarding this issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With