Promises

Handling Rejected Promises

If a promise streamed from server to client rejects, it can be caught by an ErrorBoundary. This example shows how to do that.

page.tsx
import { ErrorBoundary } from 'react-error-boundary'
import { LoadingMessage } from '@/components/LoadingMessage'

import { Suspense } from 'react'
import Table from './table'
import { ErrorFallback } from './fallback'

//just rejects after a specified delay
function getData(delay: number) {
return new Promise((resolve, reject) =>
setTimeout(() => {
//SUPER IMPORTANT: You must provide an Error to reject() or next.js will crash
//see https://github.com/vercel/next.js/issues/67863
reject(new Error('Data load failed'))
}, delay),
)
}

//passes a promise to a client component
export default function RejectedPromisePage() {
const promiseThatWillReject = getData(1000)

return (
<>
<p>This page was rendered on the server.</p>
<p>The ErrorBoundary below should catch this, but it does not.</p>

<ErrorBoundary fallback={<ErrorFallback />}>
<Suspense fallback={<LoadingMessage />}>
<Table dataPromise={promiseThatWillReject} />
</Suspense>
</ErrorBoundary>
</>
)
}

What happens here? The getData function returns a Promise that is rejected after a delay. When that happens, our Suspense fallback is replaced with the ErrorFallback component. This is a much better user experience than showing a whole page error message, which is what happens when you don't catch the error.

Live Demo

This example can't be easily inlined as it demonstrates how a full-page feels to the end user. Here it is inside an iframe, and there's a looping video below too.

This is an iframe pointing to /examples/promises/rejected-handled

Video Preview

In case the iframe doesn't work for some reason, this is a looping video of what you would see. Click the video to open the full page example in a new tab.

Similar Examples

Previous
Rejected promises