Navigation Failures

New in 3.4.0

When using router-link, Vue Router calls router.push to trigger a navigation. While the expected behavior for most links is to navigate a user to a new page, there are a few situations where users will remain on the same page:

  • Users are already on the page that they are trying to navigate to
  • A navigation guard aborts the navigation by calling next(false)
  • A navigation guard throws an error or calls next(new Error())

When using a router-link component, none of these failures will log an error. However, if you are using router.push or router.replace, you might come across an "Uncaught (in promise) Error" message followed by a more specific message in your console. Let's understand how to differentiate Navigation Failures.

Background story

In v3.2.0, Navigation Failures were exposed through the two optional callbacks of router.push: onComplete and onAbort. Since version 3.1.0, router.push and router.replace return a Promise if no onComplete/onAbort callback is provided. This Promise resolves instead of invoking onComplete and rejects instead of invoking onAbort.

Detecting Navigation Failures

Navigation Failures are Error instances with a few extra properties. To check if an error comes from the Router, use the isNavigationFailure function:

import VueRouter from 'vue-router'
const { isNavigationFailure, NavigationFailureType } = VueRouter

// trying to access the admin page
router.push('/admin').catch(failure => {
  if (isNavigationFailure(failure, NavigationFailureType.redirected)) {
    // show a small notification to the user
    showToast('Login in order to access the admin panel')
  }
})

TIP

If you omit the second parameter: isNavigationFailure(failure), it will only check if the error is a Navigation Failure.

NavigationFailureType help developers to differentiate between the various types of Navigation Failures. There are four different types:

  • redirected: next(newLocation) was called inside of a navigation guard to redirect somewhere else.
  • aborted: next(false) was called inside of a navigation guard to the navigation.
  • cancelled: A new navigation completely took place before the current navigation could finish. e.g. router.push was called while waiting inside of a navigation guard.
  • duplicated: The navigation was prevented because we are already at the target location.

All navigation failures expose to and from properties to reflect the current location as well as the target location for the navigation that failed:

// trying to access the admin page
router.push('/admin').catch(failure => {
  if (isNavigationFailure(failure, NavigationFailureType.redirected)) {
    failure.to.path // '/admin'
    failure.from.path // '/'
  }
})

In all cases, to and from are normalized route locations.