npm-tanstack--react-router

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