0
# Error Handling
1
2
Comprehensive error handling with boundaries, not found handling, custom error components, and error recovery mechanisms for robust routing applications.
3
4
## Capabilities
5
6
### Error Boundaries
7
8
React error boundaries for catching and handling route errors with recovery capabilities.
9
10
```typescript { .api }
11
/**
12
* Error boundary for catching and handling route errors
13
* @param props - Error boundary configuration
14
* @returns JSX element with error boundary functionality
15
*/
16
function CatchBoundary(props: CatchBoundaryProps): JSX.Element;
17
18
interface CatchBoundaryProps {
19
/** Function to get reset key for boundary reset */
20
getResetKey: () => string | number;
21
/** Child components to protect */
22
children: React.ReactNode;
23
/** Custom error component to render */
24
errorComponent?: ErrorRouteComponent;
25
/** Error handler callback */
26
onCatch?: (error: Error, errorInfo: React.ErrorInfo) => void;
27
}
28
29
/**
30
* Default error component for displaying errors
31
* @param props - Error component props
32
* @returns JSX element displaying error information
33
*/
34
function ErrorComponent(props: ErrorComponentProps): JSX.Element;
35
36
interface ErrorComponentProps {
37
/** The error that occurred */
38
error: any;
39
/** Error info from React */
40
info?: { componentStack: string };
41
/** Function to reset the error boundary */
42
reset?: () => void;
43
}
44
```
45
46
**Usage Examples:**
47
48
```typescript
49
import { CatchBoundary, ErrorComponent } from "@tanstack/react-router";
50
51
// Basic error boundary
52
<CatchBoundary
53
getResetKey={() => window.location.pathname}
54
errorComponent={ErrorComponent}
55
onCatch={(error, errorInfo) => {
56
console.error("Route error:", error);
57
// Send to error reporting service
58
errorReporter.captureException(error, {
59
extra: { errorInfo, route: window.location.pathname },
60
});
61
}}
62
>
63
<App />
64
</CatchBoundary>
65
66
// Custom error component
67
function CustomErrorComponent({ error, reset }) {
68
return (
69
<div className="error-container">
70
<h2>Something went wrong</h2>
71
<details>
72
<summary>Error details</summary>
73
<pre>{error.message}</pre>
74
<pre>{error.stack}</pre>
75
</details>
76
<button onClick={reset} className="retry-button">
77
Try again
78
</button>
79
</div>
80
);
81
}
82
83
// Error boundary with custom component
84
<CatchBoundary
85
getResetKey={() => Date.now()}
86
errorComponent={CustomErrorComponent}
87
>
88
<Routes />
89
</CatchBoundary>
90
```
91
92
### Not Found Error Handling
93
94
Specialized error handling for 404 not found errors with custom fallbacks.
95
96
```typescript { .api }
97
/**
98
* Create a not found error
99
* @param options - Not found error options
100
* @returns NotFoundError instance
101
*/
102
function notFound<TRouterContext = unknown>(
103
options?: NotFoundErrorOptions<TRouterContext>
104
): NotFoundError;
105
106
/**
107
* Type guard for not found errors
108
* @param obj - Object to check
109
* @returns Whether object is a not found error
110
*/
111
function isNotFound(obj: any): obj is NotFoundError;
112
113
interface NotFoundError extends Error {
114
/** Error code identifier */
115
routerCode: "NOT_FOUND";
116
/** Whether error was thrown in production */
117
isNotFound: true;
118
/** Additional data */
119
data?: any;
120
}
121
122
interface NotFoundErrorOptions<TRouterContext = unknown> {
123
/** Additional data to include */
124
data?: any;
125
}
126
127
/**
128
* Boundary specifically for handling not found errors
129
* @param props - Not found boundary props
130
* @returns JSX element with not found error handling
131
*/
132
function CatchNotFound(props: CatchNotFoundProps): JSX.Element;
133
134
interface CatchNotFoundProps {
135
/** Fallback component for not found errors */
136
fallback?: (error: NotFoundError) => React.ReactElement;
137
/** Error handler callback */
138
onCatch?: (error: Error, errorInfo: React.ErrorInfo) => void;
139
/** Child components */
140
children: React.ReactNode;
141
}
142
143
/**
144
* Default global not found component
145
* @returns JSX element for 404 errors
146
*/
147
function DefaultGlobalNotFound(): JSX.Element;
148
```
149
150
**Usage Examples:**
151
152
```typescript
153
import { notFound, isNotFound, CatchNotFound, DefaultGlobalNotFound } from "@tanstack/react-router";
154
155
// Throw not found in loader
156
const Route = createRoute({
157
path: "/posts/$postId",
158
loader: async ({ params }) => {
159
const post = await fetchPost(params.postId);
160
161
if (!post) {
162
throw notFound({
163
data: {
164
postId: params.postId,
165
message: "Post not found",
166
},
167
});
168
}
169
170
return { post };
171
},
172
});
173
174
// Handle not found in component
175
function PostLoader() {
176
try {
177
const { post } = useLoaderData();
178
return <PostDetail post={post} />;
179
} catch (error) {
180
if (isNotFound(error)) {
181
return <div>Post not found: {error.data?.postId}</div>;
182
}
183
throw error; // Re-throw other errors
184
}
185
}
186
187
// Not found boundary
188
<CatchNotFound
189
fallback={(error) => (
190
<div className="not-found">
191
<h1>404 - Page Not Found</h1>
192
<p>{error.data?.message || "The requested page could not be found."}</p>
193
<Link to="/">Go Home</Link>
194
</div>
195
)}
196
onCatch={(error, errorInfo) => {
197
console.log("Not found error:", error.data);
198
}}
199
>
200
<Routes />
201
</CatchNotFound>
202
203
// Using default not found component
204
function App() {
205
return (
206
<Router>
207
<Routes>
208
<Route path="*" component={DefaultGlobalNotFound} />
209
</Routes>
210
</Router>
211
);
212
}
213
```
214
215
### Route-Level Error Components
216
217
Error components specifically for route-level error handling.
218
219
```typescript { .api }
220
/**
221
* Route error component type
222
*/
223
type ErrorRouteComponent = React.ComponentType<{
224
error: Error;
225
info: { componentStack: string };
226
reset: () => void;
227
}>;
228
229
/**
230
* Not found route component type
231
*/
232
type NotFoundRouteComponent = React.ComponentType<{
233
data?: any;
234
}>;
235
```
236
237
**Usage Examples:**
238
239
```typescript
240
// Route with error component
241
const Route = createRoute({
242
path: "/risky-route",
243
loader: async () => {
244
// This might throw an error
245
const data = await riskyApiCall();
246
return { data };
247
},
248
component: RiskyComponent,
249
errorComponent: ({ error, reset }) => (
250
<div>
251
<h2>Error in risky route</h2>
252
<p>{error.message}</p>
253
<button onClick={reset}>Retry</button>
254
<Link to="/">Go Home</Link>
255
</div>
256
),
257
});
258
259
// Route with not found component
260
const Route = createRoute({
261
path: "/users/$userId",
262
loader: async ({ params }) => {
263
const user = await fetchUser(params.userId);
264
if (!user) {
265
throw notFound({ data: { userId: params.userId } });
266
}
267
return { user };
268
},
269
component: UserProfile,
270
notFoundComponent: ({ data }) => (
271
<div>
272
<h2>User Not Found</h2>
273
<p>User with ID "{data?.userId}" does not exist.</p>
274
<Link to="/users">View All Users</Link>
275
</div>
276
),
277
});
278
```
279
280
### Error Recovery and Reset
281
282
Utilities for recovering from errors and resetting error states.
283
284
```typescript { .api }
285
/**
286
* Error boundary reset utilities
287
*/
288
interface ErrorBoundaryReset {
289
/** Reset the error boundary */
290
reset: () => void;
291
/** Get current reset key */
292
getResetKey: () => string | number;
293
}
294
295
/**
296
* Router-level error handling
297
*/
298
interface RouterErrorHandling {
299
/** Default error handler for all routes */
300
defaultOnCatch?: (error: Error, errorInfo: React.ErrorInfo) => void;
301
/** Default error component */
302
defaultErrorComponent?: ErrorRouteComponent;
303
/** Default not found component */
304
defaultNotFoundComponent?: NotFoundRouteComponent;
305
}
306
```
307
308
**Usage Examples:**
309
310
```typescript
311
// Router with global error handling
312
const router = createRouter({
313
routeTree,
314
defaultErrorComponent: ({ error, reset }) => (
315
<div className="global-error">
316
<h1>Application Error</h1>
317
<p>{error.message}</p>
318
<button onClick={reset}>Reset Application</button>
319
</div>
320
),
321
defaultNotFoundComponent: () => (
322
<div className="global-not-found">
323
<h1>Page Not Found</h1>
324
<Link to="/">Return Home</Link>
325
</div>
326
),
327
defaultOnCatch: (error, errorInfo) => {
328
// Global error logging
329
console.error("Global route error:", error, errorInfo);
330
errorReporter.captureException(error, {
331
tags: { type: "route_error" },
332
extra: errorInfo,
333
});
334
},
335
});
336
337
// Component with error recovery
338
function RecoverableComponent() {
339
const [retryCount, setRetryCount] = useState(0);
340
const navigate = useNavigate();
341
342
const handleError = useCallback((error: Error) => {
343
if (retryCount < 3) {
344
// Auto-retry up to 3 times
345
setTimeout(() => {
346
setRetryCount(prev => prev + 1);
347
window.location.reload();
348
}, 1000);
349
} else {
350
// Navigate to error page after max retries
351
navigate({ to: "/error", state: { error: error.message } });
352
}
353
}, [retryCount, navigate]);
354
355
return (
356
<CatchBoundary
357
getResetKey={() => retryCount}
358
onCatch={handleError}
359
>
360
<RiskyComponent />
361
</CatchBoundary>
362
);
363
}
364
```
365
366
### Error Serialization
367
368
Utilities for serializing errors, particularly useful for SSR.
369
370
```typescript { .api }
371
/**
372
* Default error serializer for SSR and transport
373
* @param error - Error to serialize
374
* @returns Serialized error object
375
*/
376
function defaultSerializeError(error: Error): SerializedError;
377
378
interface SerializedError {
379
name: string;
380
message: string;
381
stack?: string;
382
}
383
```
384
385
**Usage Examples:**
386
387
```typescript
388
import { defaultSerializeError } from "@tanstack/react-router";
389
390
// Serialize errors for API responses
391
async function apiErrorHandler(error: Error) {
392
const serialized = defaultSerializeError(error);
393
394
return {
395
success: false,
396
error: serialized,
397
timestamp: Date.now(),
398
};
399
}
400
401
// Custom error serializer
402
function customSerializeError(error: Error) {
403
const base = defaultSerializeError(error);
404
405
return {
406
...base,
407
code: error.code || "UNKNOWN_ERROR",
408
timestamp: Date.now(),
409
userAgent: navigator.userAgent,
410
};
411
}
412
```
413
414
### Router State Utilities
415
416
Utilities for managing router state and initialization.
417
418
```typescript { .api }
419
/**
420
* Get initial router state for a given location
421
* @param location - Parsed location object
422
* @returns Initial router state
423
*/
424
function getInitialRouterState(location: ParsedLocation): RouterState;
425
```
426
427
**Usage Examples:**
428
429
```typescript
430
import { getInitialRouterState } from "@tanstack/react-router";
431
432
// Create initial state for SSR
433
function createServerState(url: string) {
434
const location = parseLocation(url);
435
const initialState = getInitialRouterState(location);
436
437
return {
438
...initialState,
439
isServer: true,
440
};
441
}
442
443
// Initialize router with custom state
444
const router = createRouter({
445
routeTree,
446
initialState: getInitialRouterState(currentLocation),
447
});
448
```
449
450
### Error Class Types
451
452
Specific error classes for different routing scenarios.
453
454
```typescript { .api }
455
/**
456
* Search parameter validation error
457
* Thrown when search parameter validation fails
458
*/
459
class SearchParamError extends Error {
460
name: "SearchParamError";
461
constructor(message: string);
462
}
463
464
/**
465
* Path parameter validation error
466
* Thrown when path parameter validation fails
467
*/
468
class PathParamError extends Error {
469
name: "PathParamError";
470
constructor(message: string);
471
}
472
```
473
474
**Usage Examples:**
475
476
```typescript
477
import { SearchParamError, PathParamError } from "@tanstack/react-router";
478
479
// Route with parameter validation
480
const Route = createRoute({
481
path: "/items/$itemId",
482
validateSearch: (search) => {
483
const page = Number(search.page);
484
if (isNaN(page) || page < 1) {
485
throw new SearchParamError("Page must be a positive number");
486
}
487
return { page };
488
},
489
loader: ({ params }) => {
490
if (!params.itemId.match(/^[a-zA-Z0-9]+$/)) {
491
throw new PathParamError("Invalid item ID format");
492
}
493
return fetchItem(params.itemId);
494
},
495
errorComponent: ({ error }) => {
496
if (error instanceof SearchParamError) {
497
return <div>Invalid search parameters: {error.message}</div>;
498
}
499
if (error instanceof PathParamError) {
500
return <div>Invalid path parameters: {error.message}</div>;
501
}
502
return <div>Unexpected error: {error.message}</div>;
503
},
504
});
505
```
506
507
## Types
508
509
### Error Component Types
510
511
```typescript { .api }
512
interface ErrorRouteProps {
513
error: Error;
514
info: { componentStack: string };
515
reset: () => void;
516
}
517
518
interface NotFoundRouteProps {
519
data?: any;
520
}
521
522
type ErrorRouteComponent = React.ComponentType<ErrorRouteProps>;
523
type NotFoundRouteComponent = React.ComponentType<NotFoundRouteProps>;
524
```
525
526
### Error State Types
527
528
```typescript { .api }
529
interface RouteErrorState {
530
error?: Error;
531
errorInfo?: React.ErrorInfo;
532
hasError: boolean;
533
errorBoundaryKey: string | number;
534
}
535
536
interface ErrorBoundaryState {
537
hasError: boolean;
538
error?: Error;
539
errorInfo?: React.ErrorInfo;
540
resetKey: string | number;
541
}
542
```
543
544
### Error Handling Configuration
545
546
```typescript { .api }
547
interface ErrorHandlingConfig {
548
defaultErrorComponent?: ErrorRouteComponent;
549
defaultNotFoundComponent?: NotFoundRouteComponent;
550
defaultOnCatch?: (error: Error, errorInfo: React.ErrorInfo) => void;
551
errorSerializer?: (error: Error) => any;
552
}
553
```