Some checks failed
Test examples / Test Examples (20) (push) Has been cancelled
Test examples / Test Examples (22) (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Trigger Release / start (push) Has been cancelled
Stale issue handler / stale (push) Has been cancelled
Update Font Data / create-pull-request (push) Has been cancelled
build-and-deploy / deploy-target (push) Has been cancelled
build-and-deploy / build (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / build-wasm (nodejs) (push) Has been cancelled
build-and-deploy / build-wasm (web) (push) Has been cancelled
build-and-deploy / Deploy preview tarball (push) Has been cancelled
build-and-deploy / Potentially publish release (push) Has been cancelled
build-and-deploy / publish-turbopack-npm-packages (push) Has been cancelled
build-and-deploy / Deploy examples (push) Has been cancelled
build-and-deploy / thank you, build (push) Has been cancelled
build-and-deploy / Upload Turbopack Bytesize metrics to Datadog (push) Has been cancelled
Rspack Next.js development integration tests / Rspack integration tests (push) Has been cancelled
Rspack Next.js production integration tests / Rspack integration tests (push) Has been cancelled
Turbopack Next.js development integration tests / Next.js integration tests (push) Has been cancelled
Turbopack Next.js production integration tests / Next.js integration tests (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack development test manifest (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack production test manifest (push) Has been cancelled
Upload bundler test manifests to areweturboyet.com / Upload test results (push) Has been cancelled
Update React / create-pull-request (push) Has been cancelled
test-e2e-project-reset-cron / reset-test-project (push) Has been cancelled
Notify about the top 15 issues/PRs/feature requests (most reacted) in the last 90 days / run (push) Has been cancelled
332 lines
10 KiB
Plaintext
332 lines
10 KiB
Plaintext
---
|
|
title: error.js
|
|
description: API reference for the error.js special file.
|
|
related:
|
|
title: Learn more about error handling
|
|
links:
|
|
- app/getting-started/error-handling
|
|
---
|
|
|
|
An **error** file allows you to handle unexpected runtime errors and display fallback UI.
|
|
|
|
<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 boundaries must be Client Components
|
|
|
|
import { useEffect } from 'react'
|
|
|
|
export default function Error({
|
|
error,
|
|
unstable_retry,
|
|
}: {
|
|
error: Error & { digest?: string }
|
|
unstable_retry: () => 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 re-fetching and re-rendering the segment
|
|
() => unstable_retry()
|
|
}
|
|
>
|
|
Try again
|
|
</button>
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
|
|
```jsx filename="app/dashboard/error.js" switcher
|
|
'use client' // Error boundaries must be Client Components
|
|
|
|
import { useEffect } from 'react'
|
|
|
|
export default function Error({ error, unstable_retry }) {
|
|
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 re-fetching and re-rendering the segment
|
|
() => unstable_retry()
|
|
}
|
|
>
|
|
Try again
|
|
</button>
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
|
|
`error.js` wraps 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). When an error throws within the boundary, the `error` component shows as the fallback UI.
|
|
|
|
<Image
|
|
alt="How error.js works"
|
|
srcLight="/docs/light/error-overview.png"
|
|
srcDark="/docs/dark/error-overview.png"
|
|
width="1600"
|
|
height="903"
|
|
/>
|
|
|
|
> **Good to know**:
|
|
>
|
|
> - The [React DevTools](https://react.dev/learn/react-developer-tools) allow you to toggle error boundaries to test error states.
|
|
> - If you want errors to bubble up to the parent error boundary, you can `throw` when rendering the `error` component.
|
|
|
|
In the [component hierarchy](/docs/app/getting-started/project-structure#component-hierarchy), `error.js` wraps `loading.js`, `not-found.js`, `page.js`, and nested `layout.js` files in a React error boundary. It does **not** wrap the `layout.js` or `template.js` above it in the same segment. To handle errors in the root layout, use [`global-error.js`](/docs/app/api-reference/file-conventions/error#global-error).
|
|
|
|
## Reference
|
|
|
|
### Props
|
|
|
|
#### `error`
|
|
|
|
An instance of an [`Error`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error) object forwarded to the `error.js` Client Component.
|
|
|
|
> **Good to know:** During development, the `Error` object forwarded to the client will be serialized and include the `message` of the original error for easier debugging. However, **this behavior is different in production** to avoid leaking potentially sensitive details included in the error to the client.
|
|
|
|
#### `error.message`
|
|
|
|
- Errors forwarded from Client Components show the original `Error` message.
|
|
- Errors forwarded from Server Components show a generic message with an identifier. This is to prevent leaking sensitive details. You can use the identifier, under `errors.digest`, to match the corresponding server-side logs.
|
|
|
|
#### `error.digest`
|
|
|
|
An automatically generated hash of the error thrown. It can be used to match the corresponding error in server-side logs.
|
|
|
|
#### `unstable_retry`
|
|
|
|
The cause of an error can sometimes be temporary. In these cases, trying again might resolve the issue.
|
|
|
|
An error component can use the `unstable_retry()` function to prompt the user to attempt to recover from the error. When executed, the function will try to re-fetch and 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' // Error boundaries must be Client Components
|
|
|
|
export default function Error({
|
|
error,
|
|
unstable_retry,
|
|
}: {
|
|
error: Error & { digest?: string }
|
|
unstable_retry: () => void
|
|
}) {
|
|
return (
|
|
<div>
|
|
<h2>Something went wrong!</h2>
|
|
<button onClick={() => unstable_retry()}>Try again</button>
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
|
|
```jsx filename="app/dashboard/error.js" switcher
|
|
'use client' // Error boundaries must be Client Components
|
|
|
|
export default function Error({ error, unstable_retry }) {
|
|
return (
|
|
<div>
|
|
<h2>Something went wrong!</h2>
|
|
<button onClick={() => unstable_retry()}>Try again</button>
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
|
|
#### `reset`
|
|
|
|
In most cases, you should use [`unstable_retry()`](#unstable_retry) instead. However, if you have a specific reason to clear the error state and re-render the error boundary's contents without re-fetching the contents, you can use the `reset()` function.
|
|
|
|
## Examples
|
|
|
|
### Global Error
|
|
|
|
While less common, you can handle errors in the root layout or template using `global-error.jsx`, located in the root app directory, even when leveraging [internationalization](/docs/app/guides/internationalization). Global error UI must define its own `<html>` and `<body>` tags, global styles, fonts, or other dependencies that your error page requires. This file replaces the root layout or template when active.
|
|
|
|
> **Good to know**: Error boundaries must be [Client Components](/docs/app/getting-started/server-and-client-components#using-client-components), which means that [`metadata` and `generateMetadata`](/docs/app/getting-started/metadata-and-og-images) exports are not supported in `global-error.jsx`. As an alternative, you can use the React [`<title>`](https://react.dev/reference/react-dom/components/title) component.
|
|
|
|
```tsx filename="app/global-error.tsx" switcher
|
|
'use client' // Error boundaries must be Client Components
|
|
|
|
export default function GlobalError({
|
|
error,
|
|
unstable_retry,
|
|
}: {
|
|
error: Error & { digest?: string }
|
|
unstable_retry: () => void
|
|
}) {
|
|
return (
|
|
// global-error must include html and body tags
|
|
<html>
|
|
<body>
|
|
<h2>Something went wrong!</h2>
|
|
<button onClick={() => unstable_retry()}>Try again</button>
|
|
</body>
|
|
</html>
|
|
)
|
|
}
|
|
```
|
|
|
|
```jsx filename="app/global-error.js" switcher
|
|
'use client' // Error boundaries must be Client Components
|
|
|
|
export default function GlobalError({ error, unstable_retry }) {
|
|
return (
|
|
// global-error must include html and body tags
|
|
<html>
|
|
<body>
|
|
<h2>Something went wrong!</h2>
|
|
<button onClick={() => unstable_retry()}>Try again</button>
|
|
</body>
|
|
</html>
|
|
)
|
|
}
|
|
```
|
|
|
|
### Graceful error recovery with a custom error boundary
|
|
|
|
When rendering fails on the client, it can be useful to show the last known server rendered UI for a better user experience.
|
|
|
|
The `GracefullyDegradingErrorBoundary` is an example of a custom error boundary that captures and preserves the current HTML before an error occurs. If a rendering error happens, it re-renders the captured HTML and displays a persistent notification bar to inform the user.
|
|
|
|
```tsx filename="app/dashboard/error.tsx" switcher
|
|
'use client'
|
|
|
|
import React, { Component, ErrorInfo, ReactNode } from 'react'
|
|
|
|
interface ErrorBoundaryProps {
|
|
children: ReactNode
|
|
onError?: (error: Error, errorInfo: ErrorInfo) => void
|
|
}
|
|
|
|
interface ErrorBoundaryState {
|
|
hasError: boolean
|
|
}
|
|
|
|
export class GracefullyDegradingErrorBoundary extends Component<
|
|
ErrorBoundaryProps,
|
|
ErrorBoundaryState
|
|
> {
|
|
private contentRef: React.RefObject<HTMLDivElement | null>
|
|
|
|
constructor(props: ErrorBoundaryProps) {
|
|
super(props)
|
|
this.state = { hasError: false }
|
|
this.contentRef = React.createRef()
|
|
}
|
|
|
|
static getDerivedStateFromError(_: Error): ErrorBoundaryState {
|
|
return { hasError: true }
|
|
}
|
|
|
|
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
|
if (this.props.onError) {
|
|
this.props.onError(error, errorInfo)
|
|
}
|
|
}
|
|
|
|
render() {
|
|
if (this.state.hasError) {
|
|
// Render the current HTML content without hydration
|
|
return (
|
|
<>
|
|
<div
|
|
ref={this.contentRef}
|
|
suppressHydrationWarning
|
|
dangerouslySetInnerHTML={{
|
|
__html: this.contentRef.current?.innerHTML || '',
|
|
}}
|
|
/>
|
|
<div className="fixed bottom-0 left-0 right-0 bg-red-600 text-white py-4 px-6 text-center">
|
|
<p className="font-semibold">
|
|
An error occurred during page rendering
|
|
</p>
|
|
</div>
|
|
</>
|
|
)
|
|
}
|
|
|
|
return <div ref={this.contentRef}>{this.props.children}</div>
|
|
}
|
|
}
|
|
|
|
export default GracefullyDegradingErrorBoundary
|
|
```
|
|
|
|
```jsx filename="app/dashboard/error.js" switcher
|
|
'use client'
|
|
|
|
import React, { Component, createRef } from 'react'
|
|
|
|
class GracefullyDegradingErrorBoundary extends Component {
|
|
constructor(props) {
|
|
super(props)
|
|
this.state = { hasError: false }
|
|
this.contentRef = createRef()
|
|
}
|
|
|
|
static getDerivedStateFromError(_) {
|
|
return { hasError: true }
|
|
}
|
|
|
|
componentDidCatch(error, errorInfo) {
|
|
if (this.props.onError) {
|
|
this.props.onError(error, errorInfo)
|
|
}
|
|
}
|
|
|
|
render() {
|
|
if (this.state.hasError) {
|
|
// Render the current HTML content without hydration
|
|
return (
|
|
<>
|
|
<div
|
|
ref={this.contentRef}
|
|
suppressHydrationWarning
|
|
dangerouslySetInnerHTML={{
|
|
__html: this.contentRef.current?.innerHTML || '',
|
|
}}
|
|
/>
|
|
<div className="fixed bottom-0 left-0 right-0 bg-red-600 text-white py-4 px-6 text-center">
|
|
<p className="font-semibold">
|
|
An error occurred during page rendering
|
|
</p>
|
|
</div>
|
|
</>
|
|
)
|
|
}
|
|
|
|
return <div ref={this.contentRef}>{this.props.children}</div>
|
|
}
|
|
}
|
|
|
|
export default GracefullyDegradingErrorBoundary
|
|
```
|
|
|
|
## Version History
|
|
|
|
| Version | Changes |
|
|
| --------- | ------------------------------------------- |
|
|
| `v16.2.0` | `unstable_retry` prop added. |
|
|
| `v15.2.0` | Also display `global-error` in development. |
|
|
| `v13.1.0` | `global-error` introduced. |
|
|
| `v13.0.0` | `error` introduced. |
|