Skip to content

Commit 11ae512

Browse files
committed
docs: error boundaries
1 parent 8117606 commit 11ae512

File tree

2 files changed

+116
-1
lines changed

2 files changed

+116
-1
lines changed

docs/how-to/error-boundary.md

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,115 @@
11
---
22
title: Error Boundaries
3-
hidden: true
43
---
4+
5+
# Error Boundaries
6+
7+
To avoid rendering an empty page to users, route modules will automatically catch errors in your code and render the closest `ErrorBoundary`.
8+
9+
Error boundaries are not intended for error reporting or rendering form validation errors. Please see [Form Validation](./form-validation) and [Error Reporting](./error-reporting) instead.
10+
11+
## 1. Add a root error boundary
12+
13+
All applications should at a minimum export a root error boundary. This one handles the three main cases:
14+
15+
- Thrown `data` with a status code and text
16+
- Instances of errors with a stack trace
17+
- Randomly thrown values
18+
19+
```tsx filename=root.tsx
20+
import { Route } from "./+types/root";
21+
22+
export function ErrorBoundary({
23+
error,
24+
}: Route.ErrorBoundaryProps) {
25+
console.error(error);
26+
if (isRouteErrorResponse(error)) {
27+
return (
28+
<>
29+
<h1>
30+
{error.status} {error.statusText}
31+
</h1>
32+
<p>{error.data}</p>
33+
</>
34+
);
35+
} else if (error instanceof Error) {
36+
return (
37+
<div>
38+
<h1>Error</h1>
39+
<p>{error.message}</p>
40+
<p>The stack trace is:</p>
41+
<pre>{error.stack}</pre>
42+
</div>
43+
);
44+
} else {
45+
return <h1>Unknown Error</h1>;
46+
}
47+
}
48+
```
49+
50+
## 2. Write a bug
51+
52+
It's not recommended to intentionally throw errors to force the error boundary to render as a means of control flow. Error Boundaries are primarily for catching unintentional errors in your code.
53+
54+
```tsx
55+
export async function loader() {
56+
return undefined();
57+
}
58+
```
59+
60+
This will render the `instanceof Error` branch of the UI from step 1.
61+
62+
This is not just for loaders, but for all route module APIs: loaders, actions, components, headers, links, and meta.
63+
64+
## 3. Throw data in loaders/actions
65+
66+
There are exceptions to the rule in #2, especially 404s. You can intentionally `throw data()` (with a proper status code) to the closest error boundary when your loader can't find what it needs to render the page. Throw a 404 and move on.
67+
68+
```tsx
69+
import { data } from "react-router";
70+
71+
export async function loader({ params }) {
72+
let record = await fakeDb.getRecord(params.id);
73+
if (!record) {
74+
throw data("Record Not Found", { status: 404 });
75+
}
76+
return record;
77+
}
78+
```
79+
80+
This will render the `isRouteErrorResponse` branch of the UI from step 1.
81+
82+
## 4. Nested error boundaries
83+
84+
When an error is thrown, the "closest error boundary" will be rendered. Consider these nested routes:
85+
86+
```tsx filename="routes.ts"
87+
// ✅ has error boundary
88+
route("/app", "app.tsx", [
89+
// ❌ no error boundary
90+
route("invoices", "invoices.tsx", [
91+
// ✅ has error boundary
92+
route("invoices/:id", "invoice-page.tsx", [
93+
// ❌ no error boundary
94+
route("payments", "payments.tsx"),
95+
]),
96+
]),
97+
]);
98+
```
99+
100+
The following table shows which error boundary will render given the origin of the error:
101+
102+
| error origin | rendered boundary |
103+
| ---------------- | ----------------- |
104+
| app.tsx | app.tsx |
105+
| invoices.tsx | app.tsx |
106+
| invoice-page.tsx | invoice-page.tsx |
107+
| payments.tsx | invoice-page.tsx |
108+
109+
## Error Sanitization
110+
111+
In production mode, any errors that happen on the server are automatically sanitized before being sent to the browser to prevent leaking any sensitive server information (like stack traces).
112+
113+
This means that a thrown `Error` will have a generic message and no stack trace in production in the browser. The original error is untouched on the server.
114+
115+
Also note that data sent with `throw data(yourData)` is not sanitized as the data there is intended to be rendered.

docs/how-to/error-reporting.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
title: Error Reporting
3+
hidden: true
4+
---

0 commit comments

Comments
 (0)