Skip to content

Commit c8392f5

Browse files
committed
Update docs
1 parent 8569000 commit c8392f5

File tree

1 file changed

+22
-10
lines changed

1 file changed

+22
-10
lines changed

docs/how-to/middleware.md

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -196,19 +196,31 @@ const authMiddleware = async ({ request, context }) => {
196196

197197
### `next()` and Error Handling
198198

199-
`next()` is not designed to throw errors under normal conditions, so you generally shouldn't find yourself wrapping `next` in a `try`/`catch`. The responsibility of the `next()` function is to return a `Response` for the current `Request`, so as long as that can be completed, `next()` will return the `Response` and won't `throw`. Even if a `loader` throws an error, or a component fails to render, React Router already handles those by rendering the nearest `ErrorBoundary`, so a `Response` is still generated without issue and propagated up through `next()`.
199+
React Router contains built-in error handling via the route [`ErrorBoundary`](../start/framework/route-module#errorboundary) export. Just like when a loader/acton throws, if a middleware throws an error it will be caught and handled at the appropriate `ErrorBoundary` and the `Response` will be returned through the ancestor `next()` call. This means that the `next()` function should never throw and should always return a `Response`, so you don't need to worry about wrapping it in a try/catch.
200200

201-
This behavior is important to allow middleware patterns such as automatically setting required headers on outgoing responses (i.e., committing a session) from a root middleware. If any error from a loader/action/render caused `next()` to `throw`, we'd miss the execution of ancestor middlewares on the way out and those required headers wouldn't be set.
201+
This behavior is important to allow middleware patterns such as automatically setting required headers on outgoing responses (i.e., committing a session) from a root middleware. If any error from a middleware caused `next()` to `throw`, we'd miss the execution of ancestor middlewares on the way out and those required headers wouldn't be set.
202202

203-
The only cases in which `next()` _should_ throw are if we fail to generate a `Response`. There's a few ways in which this could happen:
204-
205-
- A middleware can short circuit the rest of the request and throw a `Response` (usually a `redirect`)
206-
- If the logic directly inside of a middleware function throws, that will cause the ancestor `next()` function to throw
207-
208-
If a middleware _does_ throw (and is not caught by an ancestor middleware), then ancestor middlewares will be skipped, but React Router will still attempt to render that error in an `ErrorBoundary`.
203+
```tsx
204+
// routes/parent.tsx
205+
export const unstable_middleware = [
206+
async (_, next) => {
207+
let res = await next();
208+
// ^ res.status = 500
209+
// This response contains the ErrorBoundary
210+
return res;
211+
}
212+
]
209213

210-
- If the error threw before `next()` was called, then we don't have `loaderData` for any routes so we'll bubble to the first `ErrorBoundary` at or above all `loader` functions
211-
- If the error threw after `next()` was called, then we will bubble to the nearest `ErrorBoundary` from the throwing route
214+
// routes/parent.child.tsx
215+
export const unstable_middleware = [
216+
async (_, next) => {
217+
let res = await next();
218+
// ^ res.status = 200
219+
// This response contains the successful UI render
220+
throw new Error('Uh oh, something went wrong!)
221+
}
222+
]
223+
```
212224
213225
## Changes to `getLoadContext`/`AppLoadContext`
214226

0 commit comments

Comments
 (0)