mirror of
https://github.com/hanzoai/next.js.git
synced 2026-10-30 14:46:38 +00:00
The global error boundary is only displayed in the production (prod) environment and is not shown in the development (dev) environment. <!-- Thanks for opening a PR! Your contribution is much appreciated. To make sure your PR is handled as smoothly as possible we request that you follow the checklist sections below. Choose the right checklist for the change(s) that you're making: ## For Contributors ### Improving Documentation - Run `pnpm prettier-fix` to fix formatting issues before opening the PR. - Read the Docs Contribution Guide to ensure your contribution follows the docs guidelines: https://nextjs.org/docs/community/contribution-guide ### Adding or Updating Examples - The "examples guidelines" are followed from our contributing doc https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md - Make sure the linting passes by running `pnpm build && pnpm lint`. See https://github.com/vercel/next.js/blob/canary/contributing/repository/linting.md ### Fixing a bug - Related issues linked using `fixes #number` - Tests added. See: https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ### Adding a feature - Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. (A discussion must be opened, see https://github.com/vercel/next.js/discussions/new?category=ideas) - Related issues/discussions are linked using `fixes #number` - e2e tests added (https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs) - Documentation added - Telemetry added. In case of a feature if it's used or not. - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ## For Maintainers - Minimal description (aim for explaining to someone not on the team to understand the PR) - When linking to a Slack thread, you might want to share details of the conclusion - Link both the Linear (Fixes NEXT-xxx) and the GitHub issues - Add review comments if necessary to explain to the reviewer the logic behind a change ### What? ### Why? ### How? Closes NEXT- Fixes # --> --------- Co-authored-by: Sam Ko <[email protected]>
231 lines
8.4 KiB
Plaintext
231 lines
8.4 KiB
Plaintext
---
|
|
title: Error Handling
|
|
description: Handle runtime errors by automatically wrapping route segments and their nested children in a React Error Boundary.
|
|
related:
|
|
links:
|
|
- app/api-reference/file-conventions/error
|
|
---
|
|
|
|
The `error.js` file convention allows you to gracefully handle unexpected runtime errors in [nested routes](/docs/app/building-your-application/routing#nested-routes).
|
|
|
|
- Automatically wrap a route segment and its nested children in a [React Error Boundary](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary).
|
|
- Create error UI tailored to specific segments using the file-system hierarchy to adjust granularity.
|
|
- Isolate errors to affected segments while keeping the rest of the application functional.
|
|
- Add functionality to attempt to recover from an error without a full page reload.
|
|
|
|
Create error UI by adding an `error.js` file inside a route segment and exporting a React component:
|
|
|
|
<Image
|
|
alt="error.js special file"
|
|
srcLight="/docs/light/error-special-file.png"
|
|
srcDark="/docs/dark/error-special-file.png"
|
|
width="1600"
|
|
height="606"
|
|
/>
|
|
|
|
```tsx filename="app/dashboard/error.tsx" switcher
|
|
'use client' // Error components must be Client Components
|
|
|
|
import { useEffect } from 'react'
|
|
|
|
export default function Error({
|
|
error,
|
|
reset,
|
|
}: {
|
|
error: Error & { digest?: string }
|
|
reset: () => void
|
|
}) {
|
|
useEffect(() => {
|
|
// Log the error to an error reporting service
|
|
console.error(error)
|
|
}, [error])
|
|
|
|
return (
|
|
<div>
|
|
<h2>Something went wrong!</h2>
|
|
<button
|
|
onClick={
|
|
// Attempt to recover by trying to re-render the segment
|
|
() => reset()
|
|
}
|
|
>
|
|
Try again
|
|
</button>
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
|
|
```jsx filename="app/dashboard/error.js" switcher
|
|
'use client' // Error components must be Client Components
|
|
|
|
import { useEffect } from 'react'
|
|
|
|
export default function Error({ error, reset }) {
|
|
useEffect(() => {
|
|
// Log the error to an error reporting service
|
|
console.error(error)
|
|
}, [error])
|
|
|
|
return (
|
|
<div>
|
|
<h2>Something went wrong!</h2>
|
|
<button
|
|
onClick={
|
|
// Attempt to recover by trying to re-render the segment
|
|
() => reset()
|
|
}
|
|
>
|
|
Try again
|
|
</button>
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
|
|
### How `error.js` Works
|
|
|
|
<Image
|
|
alt="How error.js works"
|
|
srcLight="/docs/light/error-overview.png"
|
|
srcDark="/docs/dark/error-overview.png"
|
|
width="1600"
|
|
height="903"
|
|
/>
|
|
|
|
- `error.js` automatically creates a [React Error Boundary](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) that **wraps** a nested child segment or `page.js` component.
|
|
- The React component exported from the `error.js` file is used as the **fallback** component.
|
|
- If an error is thrown within the error boundary, the error is **contained**, and the fallback component is **rendered**.
|
|
- When the fallback error component is active, layouts **above** the error boundary **maintain** their state and **remain** interactive, and the error component can display functionality to recover from the error.
|
|
|
|
### Recovering From Errors
|
|
|
|
The cause of an error can sometimes be temporary. In these cases, simply trying again might resolve the issue.
|
|
|
|
An error component can use the `reset()` function to prompt the user to attempt to recover from the error. When executed, the function will try to re-render the Error boundary's contents. If successful, the fallback error component is replaced with the result of the re-render.
|
|
|
|
```tsx filename="app/dashboard/error.tsx" switcher
|
|
'use client'
|
|
|
|
export default function Error({
|
|
error,
|
|
reset,
|
|
}: {
|
|
error: Error & { digest?: string }
|
|
reset: () => void
|
|
}) {
|
|
return (
|
|
<div>
|
|
<h2>Something went wrong!</h2>
|
|
<button onClick={() => reset()}>Try again</button>
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
|
|
```jsx filename="app/dashboard/error.js" switcher
|
|
'use client'
|
|
|
|
export default function Error({ error, reset }) {
|
|
return (
|
|
<div>
|
|
<h2>Something went wrong!</h2>
|
|
<button onClick={() => reset()}>Try again</button>
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
|
|
### Nested Routes
|
|
|
|
React components created through [special files](/docs/app/building-your-application/routing#file-conventions) are rendered in a [specific nested hierarchy](/docs/app/building-your-application/routing#component-hierarchy).
|
|
|
|
For example, a nested route with two segments that both include `layout.js` and `error.js` files are rendered in the following _simplified_ component hierarchy:
|
|
|
|
<Image
|
|
alt="Nested Error Component Hierarchy"
|
|
srcLight="/docs/light/nested-error-component-hierarchy.png"
|
|
srcDark="/docs/dark/nested-error-component-hierarchy.png"
|
|
width="1600"
|
|
height="687"
|
|
/>
|
|
|
|
The nested component hierarchy has implications for the behavior of `error.js` files across a nested route:
|
|
|
|
- Errors bubble up to the nearest parent error boundary. This means an `error.js` file will handle errors for all its nested child segments. More or less granular error UI can be achieved by placing `error.js` files at different levels in the nested folders of a route.
|
|
- An `error.js` boundary will **not** handle errors thrown in a `layout.js` component in the **same** segment because the error boundary is nested **inside** that layout's component.
|
|
|
|
### Handling Errors in Layouts
|
|
|
|
`error.js` boundaries do **not** catch errors thrown in `layout.js` or `template.js` components of the **same segment**. This [intentional hierarchy](#nested-routes) keeps important UI that is shared between sibling routes (such as navigation) visible and functional when an error occurs.
|
|
|
|
To handle errors within a specific layout or template, place an `error.js` file in the layout's parent segment.
|
|
|
|
To handle errors within the root layout or template, use a variation of `error.js` called `global-error.js`.
|
|
|
|
### Handling Errors in Root Layouts
|
|
|
|
The root `app/error.js` boundary does **not** catch errors thrown in the root `app/layout.js` or `app/template.js` component.
|
|
|
|
To specifically handle errors in these root components, use a variation of `error.js` called `app/global-error.js` located in the root `app` directory.
|
|
|
|
Unlike the root `error.js`, the `global-error.js` error boundary wraps the **entire** application, and its fallback component replaces the root layout when active. Because of this, it is important to note that `global-error.js` **must** define its own `<html>` and `<body>` tags.
|
|
|
|
`global-error.js` is the least granular error UI and can be considered "catch-all" error handling for the whole application. It is unlikely to be triggered often as root components are typically less dynamic, and other `error.js` boundaries will catch most errors.
|
|
|
|
Even if a `global-error.js` is defined, it is still recommended to define a root `error.js` whose fallback component will be rendered **within** the root layout, which includes globally shared UI and branding.
|
|
|
|
```tsx filename="app/global-error.tsx" switcher
|
|
'use client'
|
|
|
|
export default function GlobalError({
|
|
error,
|
|
reset,
|
|
}: {
|
|
error: Error & { digest?: string }
|
|
reset: () => void
|
|
}) {
|
|
return (
|
|
<html>
|
|
<body>
|
|
<h2>Something went wrong!</h2>
|
|
<button onClick={() => reset()}>Try again</button>
|
|
</body>
|
|
</html>
|
|
)
|
|
}
|
|
```
|
|
|
|
```jsx filename="app/global-error.js" switcher
|
|
'use client'
|
|
|
|
export default function GlobalError({ error, reset }) {
|
|
return (
|
|
<html>
|
|
<body>
|
|
<h2>Something went wrong!</h2>
|
|
<button onClick={() => reset()}>Try again</button>
|
|
</body>
|
|
</html>
|
|
)
|
|
}
|
|
```
|
|
|
|
> **Good to know**:
|
|
>
|
|
> - `global-error.js` is only enabled in production. In development, our error overlay will show instead.
|
|
|
|
### Handling Server Errors
|
|
|
|
If an error is thrown inside a Server Component, Next.js will forward an `Error` object (stripped of sensitive error information in production) to the nearest `error.js` file as the `error` prop.
|
|
|
|
#### Securing Sensitive Error Information
|
|
|
|
During production, the `Error` object forwarded to the client only includes a generic `message` and `digest` property.
|
|
|
|
This is a security precaution to avoid leaking potentially sensitive details included in the error to the client.
|
|
|
|
The `message` property contains a generic message about the error and the `digest` property contains an automatically generated hash of the error that can be used to match the corresponding error in server-side logs.
|
|
|
|
During development, the `Error` object forwarded to the client will be serialized and include the `message` of the original error for easier debugging.
|