@esmx/router provides a hierarchy of error classes for different routing failure scenarios. All route errors extend the base RouteError class, making it easy to catch and handle specific error types.
class RouteError extends Error {
public readonly code: string;
public readonly to: Route;
public readonly from: Route | null;
constructor(
message: string,
code: string,
to: Route,
from: Route | null
);
}Base class for all route-related errors.
Properties:
name: 'RouteError'code: Error code string identifying the error typeto: The target Route object when the error occurredfrom: The source Route object (may be null for initial navigation)message: Human-readable error descriptionimport { RouteError } from '@esmx/router';
try {
await router.push('/target');
} catch (error) {
if (error instanceof RouteError) {
console.log('Route error:', error.code);
console.log('Target:', error.to.path);
console.log('From:', error.from?.path);
}
}class RouteTaskCancelledError extends RouteError {
public readonly taskName: string;
constructor(
taskName: string,
to: Route,
from: Route | null
);
}Thrown when a route task is cancelled, typically because a new navigation was triggered before the current one completed.
Properties:
name: 'RouteTaskCancelledError'code: 'ROUTE_TASK_CANCELLED'taskName: Name of the cancelled taskimport { RouteTaskCancelledError } from '@esmx/router';
try {
await router.push('/slow-page');
} catch (error) {
if (error instanceof RouteTaskCancelledError) {
console.log(`Task "${error.taskName}" was cancelled`);
// This is normal — another navigation replaced this one
}
}class RouteTaskExecutionError extends RouteError {
public readonly taskName: string;
public readonly originalError: Error;
constructor(
taskName: string,
to: Route,
from: Route | null,
originalError?: unknown
);
}Thrown when a route task (such as a guard or handle hook) throws an error during execution.
Properties:
name: 'RouteTaskExecutionError'code: 'ROUTE_TASK_EXECUTION_ERROR'taskName: Name of the failed taskoriginalError: The original error that caused the failureimport { RouteTaskExecutionError } from '@esmx/router';
try {
await router.push('/page');
} catch (error) {
if (error instanceof RouteTaskExecutionError) {
console.error(
`Task "${error.taskName}" failed:`,
error.originalError.message
);
}
}class RouteNavigationAbortedError extends RouteError {
public readonly taskName: string;
constructor(
taskName: string,
to: Route,
from: Route | null
);
}Thrown when navigation is explicitly aborted by a guard returning false.
Properties:
name: 'RouteNavigationAbortedError'code: 'ROUTE_NAVIGATION_ABORTED'taskName: Name of the guard that aborted navigationimport { RouteNavigationAbortedError } from '@esmx/router';
router.beforeEach((to) => {
if (to.meta.restricted) {
return false; // This will cause RouteNavigationAbortedError
}
});
try {
await router.push('/restricted');
} catch (error) {
if (error instanceof RouteNavigationAbortedError) {
console.log(`Navigation aborted by: ${error.taskName}`);
}
}class RouteSelfRedirectionError extends RouteError {
constructor(
fullPath: string,
to: Route,
from: Route | null
);
}Thrown when a redirect would cause an infinite loop by redirecting to the same path.
Properties:
name: 'RouteSelfRedirectionError'code: 'ROUTE_SELF_REDIRECTION'import { RouteSelfRedirectionError } from '@esmx/router';
// This configuration would cause a self-redirection error:
// { path: '/loop', redirect: '/loop' }
try {
await router.push('/loop');
} catch (error) {
if (error instanceof RouteSelfRedirectionError) {
console.error('Redirect loop detected:', error.message);
}
}All error classes inherit from RouteError, which inherits from the standard Error class:
Error
└── RouteError
├── RouteTaskCancelledError
├── RouteTaskExecutionError
├── RouteNavigationAbortedError
└── RouteSelfRedirectionErrorimport { RouteError } from '@esmx/router';
try {
await router.push('/target');
} catch (error) {
if (error instanceof RouteError) {
switch (error.code) {
case 'ROUTE_TASK_CANCELLED':
// Navigation was replaced — usually safe to ignore
break;
case 'ROUTE_NAVIGATION_ABORTED':
// Guard rejected navigation
showNotification('Navigation blocked');
break;
case 'ROUTE_TASK_EXECUTION_ERROR':
// A guard or handler threw an error
reportError(error);
break;
case 'ROUTE_SELF_REDIRECTION':
// Redirect loop detected
console.error('Configuration error:', error.message);
break;
}
}
}Cancellation errors are common during rapid navigation (e.g., user clicking multiple links quickly). They are generally safe to ignore:
import { RouteTaskCancelledError } from '@esmx/router';
try {
await router.push('/target');
} catch (error) {
if (error instanceof RouteTaskCancelledError) {
return; // Safe to ignore
}
throw error; // Re-throw unexpected errors
}