- Spec files
npm-tanstack--react-router
Describes: pkg:npm/@tanstack/react-router@1.132.x
- Description
- Modern and scalable routing for React applications with built-in data fetching, caching, and state management capabilities
- Author
- tessl
- Last updated
How to use
npx @tessl/cli registry install tessl/npm-tanstack--react-router@1.132.0
error-handling.md docs/
1# Error Handling23Comprehensive error handling with boundaries, not found handling, custom error components, and error recovery mechanisms for robust routing applications.45## Capabilities67### Error Boundaries89React error boundaries for catching and handling route errors with recovery capabilities.1011```typescript { .api }12/**13* Error boundary for catching and handling route errors14* @param props - Error boundary configuration15* @returns JSX element with error boundary functionality16*/17function CatchBoundary(props: CatchBoundaryProps): JSX.Element;1819interface CatchBoundaryProps {20/** Function to get reset key for boundary reset */21getResetKey: () => string | number;22/** Child components to protect */23children: React.ReactNode;24/** Custom error component to render */25errorComponent?: ErrorRouteComponent;26/** Error handler callback */27onCatch?: (error: Error, errorInfo: React.ErrorInfo) => void;28}2930/**31* Default error component for displaying errors32* @param props - Error component props33* @returns JSX element displaying error information34*/35function ErrorComponent(props: ErrorComponentProps): JSX.Element;3637interface ErrorComponentProps {38/** The error that occurred */39error: any;40/** Error info from React */41info?: { componentStack: string };42/** Function to reset the error boundary */43reset?: () => void;44}45```4647**Usage Examples:**4849```typescript50import { CatchBoundary, ErrorComponent } from "@tanstack/react-router";5152// Basic error boundary53<CatchBoundary54getResetKey={() => window.location.pathname}55errorComponent={ErrorComponent}56onCatch={(error, errorInfo) => {57console.error("Route error:", error);58// Send to error reporting service59errorReporter.captureException(error, {60extra: { errorInfo, route: window.location.pathname },61});62}}63>64<App />65</CatchBoundary>6667// Custom error component68function CustomErrorComponent({ error, reset }) {69return (70<div className="error-container">71<h2>Something went wrong</h2>72<details>73<summary>Error details</summary>74<pre>{error.message}</pre>75<pre>{error.stack}</pre>76</details>77<button onClick={reset} className="retry-button">78Try again79</button>80</div>81);82}8384// Error boundary with custom component85<CatchBoundary86getResetKey={() => Date.now()}87errorComponent={CustomErrorComponent}88>89<Routes />90</CatchBoundary>91```9293### Not Found Error Handling9495Specialized error handling for 404 not found errors with custom fallbacks.9697```typescript { .api }98/**99* Create a not found error100* @param options - Not found error options101* @returns NotFoundError instance102*/103function notFound<TRouterContext = unknown>(104options?: NotFoundErrorOptions<TRouterContext>105): NotFoundError;106107/**108* Type guard for not found errors109* @param obj - Object to check110* @returns Whether object is a not found error111*/112function isNotFound(obj: any): obj is NotFoundError;113114interface NotFoundError extends Error {115/** Error code identifier */116routerCode: "NOT_FOUND";117/** Whether error was thrown in production */118isNotFound: true;119/** Additional data */120data?: any;121}122123interface NotFoundErrorOptions<TRouterContext = unknown> {124/** Additional data to include */125data?: any;126}127128/**129* Boundary specifically for handling not found errors130* @param props - Not found boundary props131* @returns JSX element with not found error handling132*/133function CatchNotFound(props: CatchNotFoundProps): JSX.Element;134135interface CatchNotFoundProps {136/** Fallback component for not found errors */137fallback?: (error: NotFoundError) => React.ReactElement;138/** Error handler callback */139onCatch?: (error: Error, errorInfo: React.ErrorInfo) => void;140/** Child components */141children: React.ReactNode;142}143144/**145* Default global not found component146* @returns JSX element for 404 errors147*/148function DefaultGlobalNotFound(): JSX.Element;149```150151**Usage Examples:**152153```typescript154import { notFound, isNotFound, CatchNotFound, DefaultGlobalNotFound } from "@tanstack/react-router";155156// Throw not found in loader157const Route = createRoute({158path: "/posts/$postId",159loader: async ({ params }) => {160const post = await fetchPost(params.postId);161162if (!post) {163throw notFound({164data: {165postId: params.postId,166message: "Post not found",167},168});169}170171return { post };172},173});174175// Handle not found in component176function PostLoader() {177try {178const { post } = useLoaderData();179return <PostDetail post={post} />;180} catch (error) {181if (isNotFound(error)) {182return <div>Post not found: {error.data?.postId}</div>;183}184throw error; // Re-throw other errors185}186}187188// Not found boundary189<CatchNotFound190fallback={(error) => (191<div className="not-found">192<h1>404 - Page Not Found</h1>193<p>{error.data?.message || "The requested page could not be found."}</p>194<Link to="/">Go Home</Link>195</div>196)}197onCatch={(error, errorInfo) => {198console.log("Not found error:", error.data);199}}200>201<Routes />202</CatchNotFound>203204// Using default not found component205function App() {206return (207<Router>208<Routes>209<Route path="*" component={DefaultGlobalNotFound} />210</Routes>211</Router>212);213}214```215216### Route-Level Error Components217218Error components specifically for route-level error handling.219220```typescript { .api }221/**222* Route error component type223*/224type ErrorRouteComponent = React.ComponentType<{225error: Error;226info: { componentStack: string };227reset: () => void;228}>;229230/**231* Not found route component type232*/233type NotFoundRouteComponent = React.ComponentType<{234data?: any;235}>;236```237238**Usage Examples:**239240```typescript241// Route with error component242const Route = createRoute({243path: "/risky-route",244loader: async () => {245// This might throw an error246const data = await riskyApiCall();247return { data };248},249component: RiskyComponent,250errorComponent: ({ error, reset }) => (251<div>252<h2>Error in risky route</h2>253<p>{error.message}</p>254<button onClick={reset}>Retry</button>255<Link to="/">Go Home</Link>256</div>257),258});259260// Route with not found component261const Route = createRoute({262path: "/users/$userId",263loader: async ({ params }) => {264const user = await fetchUser(params.userId);265if (!user) {266throw notFound({ data: { userId: params.userId } });267}268return { user };269},270component: UserProfile,271notFoundComponent: ({ data }) => (272<div>273<h2>User Not Found</h2>274<p>User with ID "{data?.userId}" does not exist.</p>275<Link to="/users">View All Users</Link>276</div>277),278});279```280281### Error Recovery and Reset282283Utilities for recovering from errors and resetting error states.284285```typescript { .api }286/**287* Error boundary reset utilities288*/289interface ErrorBoundaryReset {290/** Reset the error boundary */291reset: () => void;292/** Get current reset key */293getResetKey: () => string | number;294}295296/**297* Router-level error handling298*/299interface RouterErrorHandling {300/** Default error handler for all routes */301defaultOnCatch?: (error: Error, errorInfo: React.ErrorInfo) => void;302/** Default error component */303defaultErrorComponent?: ErrorRouteComponent;304/** Default not found component */305defaultNotFoundComponent?: NotFoundRouteComponent;306}307```308309**Usage Examples:**310311```typescript312// Router with global error handling313const router = createRouter({314routeTree,315defaultErrorComponent: ({ error, reset }) => (316<div className="global-error">317<h1>Application Error</h1>318<p>{error.message}</p>319<button onClick={reset}>Reset Application</button>320</div>321),322defaultNotFoundComponent: () => (323<div className="global-not-found">324<h1>Page Not Found</h1>325<Link to="/">Return Home</Link>326</div>327),328defaultOnCatch: (error, errorInfo) => {329// Global error logging330console.error("Global route error:", error, errorInfo);331errorReporter.captureException(error, {332tags: { type: "route_error" },333extra: errorInfo,334});335},336});337338// Component with error recovery339function RecoverableComponent() {340const [retryCount, setRetryCount] = useState(0);341const navigate = useNavigate();342343const handleError = useCallback((error: Error) => {344if (retryCount < 3) {345// Auto-retry up to 3 times346setTimeout(() => {347setRetryCount(prev => prev + 1);348window.location.reload();349}, 1000);350} else {351// Navigate to error page after max retries352navigate({ to: "/error", state: { error: error.message } });353}354}, [retryCount, navigate]);355356return (357<CatchBoundary358getResetKey={() => retryCount}359onCatch={handleError}360>361<RiskyComponent />362</CatchBoundary>363);364}365```366367### Error Serialization368369Utilities for serializing errors, particularly useful for SSR.370371```typescript { .api }372/**373* Default error serializer for SSR and transport374* @param error - Error to serialize375* @returns Serialized error object376*/377function defaultSerializeError(error: Error): SerializedError;378379interface SerializedError {380name: string;381message: string;382stack?: string;383}384```385386**Usage Examples:**387388```typescript389import { defaultSerializeError } from "@tanstack/react-router";390391// Serialize errors for API responses392async function apiErrorHandler(error: Error) {393const serialized = defaultSerializeError(error);394395return {396success: false,397error: serialized,398timestamp: Date.now(),399};400}401402// Custom error serializer403function customSerializeError(error: Error) {404const base = defaultSerializeError(error);405406return {407...base,408code: error.code || "UNKNOWN_ERROR",409timestamp: Date.now(),410userAgent: navigator.userAgent,411};412}413```414415### Router State Utilities416417Utilities for managing router state and initialization.418419```typescript { .api }420/**421* Get initial router state for a given location422* @param location - Parsed location object423* @returns Initial router state424*/425function getInitialRouterState(location: ParsedLocation): RouterState;426```427428**Usage Examples:**429430```typescript431import { getInitialRouterState } from "@tanstack/react-router";432433// Create initial state for SSR434function createServerState(url: string) {435const location = parseLocation(url);436const initialState = getInitialRouterState(location);437438return {439...initialState,440isServer: true,441};442}443444// Initialize router with custom state445const router = createRouter({446routeTree,447initialState: getInitialRouterState(currentLocation),448});449```450451### Error Class Types452453Specific error classes for different routing scenarios.454455```typescript { .api }456/**457* Search parameter validation error458* Thrown when search parameter validation fails459*/460class SearchParamError extends Error {461name: "SearchParamError";462constructor(message: string);463}464465/**466* Path parameter validation error467* Thrown when path parameter validation fails468*/469class PathParamError extends Error {470name: "PathParamError";471constructor(message: string);472}473```474475**Usage Examples:**476477```typescript478import { SearchParamError, PathParamError } from "@tanstack/react-router";479480// Route with parameter validation481const Route = createRoute({482path: "/items/$itemId",483validateSearch: (search) => {484const page = Number(search.page);485if (isNaN(page) || page < 1) {486throw new SearchParamError("Page must be a positive number");487}488return { page };489},490loader: ({ params }) => {491if (!params.itemId.match(/^[a-zA-Z0-9]+$/)) {492throw new PathParamError("Invalid item ID format");493}494return fetchItem(params.itemId);495},496errorComponent: ({ error }) => {497if (error instanceof SearchParamError) {498return <div>Invalid search parameters: {error.message}</div>;499}500if (error instanceof PathParamError) {501return <div>Invalid path parameters: {error.message}</div>;502}503return <div>Unexpected error: {error.message}</div>;504},505});506```507508## Types509510### Error Component Types511512```typescript { .api }513interface ErrorRouteProps {514error: Error;515info: { componentStack: string };516reset: () => void;517}518519interface NotFoundRouteProps {520data?: any;521}522523type ErrorRouteComponent = React.ComponentType<ErrorRouteProps>;524type NotFoundRouteComponent = React.ComponentType<NotFoundRouteProps>;525```526527### Error State Types528529```typescript { .api }530interface RouteErrorState {531error?: Error;532errorInfo?: React.ErrorInfo;533hasError: boolean;534errorBoundaryKey: string | number;535}536537interface ErrorBoundaryState {538hasError: boolean;539error?: Error;540errorInfo?: React.ErrorInfo;541resetKey: string | number;542}543```544545### Error Handling Configuration546547```typescript { .api }548interface ErrorHandlingConfig {549defaultErrorComponent?: ErrorRouteComponent;550defaultNotFoundComponent?: NotFoundRouteComponent;551defaultOnCatch?: (error: Error, errorInfo: React.ErrorInfo) => void;552errorSerializer?: (error: Error) => any;553}554```