RouterError - greydragon888/real-router GitHub Wiki

RouterError

Overview

The RouterError class represents errors that occur during router operations. It extends the native Error class with additional properties for error codes, route segments, paths, and redirect states.

Type Definition

interface RouterError extends Error {
  [key: string]: unknown;

  readonly code: string;
  readonly segment: string | undefined;
  readonly path: string | undefined;
  readonly redirect: State | undefined;

  setCode: (code: string) => void;
  setErrorInstance: (err: Error) => void;
  setAdditionalFields: (fields: Record<string, unknown>) => void;
  hasField: (key: string) => boolean;
  getField: (key: string) => unknown;
  toJSON: () => Record<string, unknown>;
}

Properties

Property Type Description
code string Error code identifier (see Error Codes)
segment string | undefined Route segment where error occurred
path string | undefined Path being navigated to when error occurred
redirect State | undefined Redirect state if error includes redirect info
message string Error message (inherited from Error)
name string Always "RouterError"
stack string Stack trace (inherited from Error)

Methods

setCode

setCode(code: string): void

Updates the error code. If the code is a standard error code, the message is also updated.

const error = new RouterError("ROUTE_NOT_FOUND");
error.setCode("CANNOT_ACTIVATE");
console.log(error.code); // "CANNOT_ACTIVATE"

setErrorInstance

setErrorInstance(err: Error): void

Copies properties from a native Error instance (message, stack, etc.).

try {
  throw new Error("Original error");
} catch (e) {
  const routerError = new RouterError("TRANSITION_ERR");
  routerError.setErrorInstance(e);
  console.log(routerError.message); // "Original error"
}

setAdditionalFields

setAdditionalFields(fields: Record<string, unknown>): void

Adds custom fields to the error. Reserved properties (code, segment, path, redirect) are ignored.

const error = new RouterError("TRANSITION_ERR");
error.setAdditionalFields({
  userId: "123",
  attemptedAction: "delete",
});

hasField

hasField(key: string): boolean

Checks if a custom field exists on the error.

if (error.hasField("userId")) {
  console.log("User ID:", error.getField("userId"));
}

getField

getField(key: string): unknown

Retrieves a custom field value.

const userId = error.getField("userId") as string;

toJSON

toJSON(): Record<string, unknown>

Serializes the error to a JSON-compatible object. Includes code, message, segment, path, redirect, and all custom fields.

const error = new RouterError("ROUTE_NOT_FOUND", {
  path: "/unknown",
  segment: "unknown",
});
console.log(JSON.stringify(error.toJSON(), null, 2));
// {
//   "code": "ROUTE_NOT_FOUND",
//   "message": "ROUTE_NOT_FOUND",
//   "segment": "unknown",
//   "path": "/unknown"
// }

Constructor

constructor(
  code: string,
  options?: {
    message?: string;
    segment?: string;
    path?: string;
    redirect?: State;
    [key: string]: unknown;
  }
)

Creates a new RouterError with the specified code and optional properties.

// Basic error
const error1 = new RouterError("ROUTE_NOT_FOUND");

// With message
const error2 = new RouterError("CANNOT_ACTIVATE", {
  message: "User not authenticated",
});

// With redirect
const error3 = new RouterError("CANNOT_ACTIVATE", {
  redirect: { name: "login", params: {}, path: "/login" },
});

// With custom fields
const error4 = new RouterError("TRANSITION_ERR", {
  path: "/users/123",
  segment: "users.profile",
  originalError: someError,
  context: { action: "view" },
});

Usage Examples

Handling Navigation Errors

router
  .navigate("protected-route")
  .then((state) => {
    console.log("Navigated to:", state.name);
  })
  .catch((error) => {
    if (error.code === "CANNOT_ACTIVATE") {
      console.log("Access denied");
      if (error.redirect) {
        router.navigate(error.redirect.name, error.redirect.params);
      }
    } else if (error.code === "ROUTE_NOT_FOUND") {
      console.log("Route does not exist:", error.path);
    }
  });

In Guards

const authGuard = (router) => (toState, fromState) => {
  if (!isAuthenticated()) {
    throw new RouterError("CANNOT_ACTIVATE", {
      message: "Authentication required",
      redirect: { name: "login", params: { returnUrl: toState.path } },
    });
  }
  return true;
};

Error Handling with Promises

try {
  const state = await router.navigate("users");
  console.log("Success:", state);
} catch (error) {
  console.error("Navigation failed:", error.code);
  console.error("Message:", error.message);
  if (error.redirect) {
    console.log("Redirect to:", error.redirect.name);
  }
}

Event Listeners

import { getPluginApi } from "@real-router/core/api";

getPluginApi(router).addEventListener("TRANSITION_ERROR", ({ error }) => {
  // Log error for monitoring
  logError({
    code: error.code,
    message: error.message,
    path: error.path,
    segment: error.segment,
    ...error.toJSON(),
  });
});

Error Codes

See Error Codes for a complete list of error codes and their meanings.

Code Description
NOT_STARTED Router hasn't been started
ALREADY_STARTED Router already started
NO_START_PATH_OR_STATE No initial path provided
ROUTE_NOT_FOUND Route doesn't exist
SAME_STATES Navigating to current state
CANNOT_DEACTIVATE Deactivation guard rejected
CANNOT_ACTIVATE Activation guard rejected
TRANSITION_ERR Transition error
CANCELLED Navigation cancelled

Important Notes

  • RouterError extends native Error class
  • redirect property is frozen (immutable) if provided
  • Reserved properties cannot be overwritten via setAdditionalFields
  • Methods like setCode, setErrorInstance are silently ignored in setAdditionalFields
  • Error is compatible with JSON serialization via toJSON()

Related