Files
Jiwon ChoiandGitHub 74ce6b2e2f Reapply "Stabilize catchError and retry by removing unstable_ prefix" (#94623)
### What?

Reverts #94617, which had reverted #94610. This re-lands the
stabilization of the `catchError` API and the `retry` error prop by
removing their `unstable_` prefix across source, docs, and tests.

### Why?

#94610 was reverted in #94617 to unblock another change. This re-applies
it now that it is no longer blocked.

### How?

`git revert` of the revert commit. The repo's custom errors.json merge
driver handled the error registry: the original codes `1324`/`1325` had
been reclaimed by `instant` errors after the revert, so the reintroduced
messages were minted as new codes `1360` (`retry()` can only be used in
the App Router) and `1361` (`catchError` can only be used in Client
Components), keeping errors.json append-only.

The docs changelog adds `v16.3.0 | catchError became stable.` while
retaining the historical `v16.2.0 | unstable_catchError introduced.`
row.

### Verification

- `pnpm update-error-codes` (check_error_codes passes; errors.json in
sync)
- `pnpm build` (full JS build, exit 0)
- `pnpm --filter=next types` (exit 0)
- Not run: Rust/cargo build (`react_server_components.rs` change is a
one-line allow-list string revert; left to CI)

<!-- NEXT_JS_LLM_PR -->
2026-06-09 16:11:44 -07:00

61 lines
1.4 KiB
TypeScript

import { useState } from 'react'
import { catchError, type ErrorInfo } from 'next/error'
function ErrorFallback(
{ clearError }: { clearError: () => void },
{ error, reset, retry }: ErrorInfo
) {
const [retryError, setRetryError] = useState<string | null>(null)
return (
<>
<p id="pages-error-message">{(error as Error).message}</p>
<button
id="pages-reset"
onClick={() => {
clearError()
reset()
}}
>
Reset
</button>
<button
id="pages-retry"
onClick={() => {
try {
retry()
} catch (error) {
setRetryError((error as Error).message)
}
}}
>
Retry
</button>
{retryError ? <p id="pages-retry-error">{retryError}</p> : null}
</>
)
}
const ErrorBoundary = catchError(ErrorFallback)
function ErrorThrower({ shouldThrow }: { shouldThrow: boolean }) {
if (shouldThrow) {
throw new Error('this is a pages test')
}
return null
}
export default function Page() {
const [shouldThrow, setShouldThrow] = useState(false)
return (
<ErrorBoundary clearError={() => setShouldThrow(false)}>
<button id="pages-trigger" onClick={() => setShouldThrow(true)}>
Trigger Error!
</button>
<ErrorThrower shouldThrow={shouldThrow} />
</ErrorBoundary>
)
}