エラー画面の作り方。error.tsx と global-error
error.tsx は、ページで起きた例外を受け止めて、代わりの画面を出すファイルです。
いちばん小さい形
// app/error.tsx
'use client'
export default function Error({
error,
retry,
}: {
error: Error & { digest?: string }
retry: () => void
}) {
return (
<div>
<p>表示できませんでした。時間をおいてもう一度お試しください。</p>
<p>{`エラー番号: ${error.digest ?? '-'}`}</p>
<button onClick={() => retry()}>もう一度読み込む</button>
</div>
)
}
'use client' が要ります。付けないとビルドが止まります(この問題)。
retry は、公式ドキュメントによると、中身を読み込み直して描き直す関数です。Next.js 16.3 で安定版になり、以前からある reset より推奨されています。16.3.5 の型にはどちらもあります。
本番では、本当の文言は届かない
データベースにつながらなかった、のような例外の文言をそのまま画面に出したくなります。本番でページが例外を投げたときに、何が見えるかを確かめました。
| 見る場所 | 出たもの |
|---|---|
| error.tsx の error.message | Minified React error #441 …(決まった文言) |
| error.tsx の error.digest | 番号(例: 2288897430) |
| ブラウザのコンソール | Minified React error #441 …(決まった文言) |
| サーバーのログ | throw した本当の文言と、同じ digest |
本当の文言は、サーバーのログにしか出ませんでした。例外の文言には接続先やパスワードのような秘密が入ることがあるので、本番ではブラウザへ送らない作りです。
公式ドキュメントによると、Client Component で起きた例外は元の文言のまま届きます。置き換わるのは、サーバーで起きた例外です。
どの error.tsx が受け止めるか
error.tsx は、同じ階層の page を包む位置に入ります。同じ階層の layout は包みません。
| 例外が起きた場所 | 出た画面 |
|---|---|
| app/shop/page.tsx | app/shop/error.tsx |
| app/shop/layout.tsx | app/error.tsx(ひとつ上) |
| app/layout.tsx(ルート) | app/global-error.tsx |
| app/layout.tsx で、global-error.tsx が無い | Next.js の既定の画面(英語) |
- Serverapp/shop/layout.tsx が例外を投げる
app/shop/error.tsx はこの layout の内側にある。
- Server内側の error.tsx には届かない
例外は外側へ上がる。
- Browserapp/error.tsx が出る
shop の画面ではなく、全体のエラー画面になる。
layout でデータを読むと、その失敗で画面全体のエラー画面になります。失敗しうる読み込みは、できるだけ page の側に置いてください。
ルートの layout には global-error.tsx
ルートの layout が例外を投げると、app/error.tsx には届きません。受け止めるのは app/global-error.tsx です。
// app/global-error.tsx
'use client'
export default function GlobalError({ retry }: { retry: () => void }) {
return (
<html lang="ja">
<body>
<p>ただいま表示できません。</p>
<button onClick={() => retry()}>もう一度読み込む</button>
</body>
</html>
)
}
ルートの layout の代わりに描かれるので、html と body を自分で書きます。公式ドキュメントによると、アプリ全体の CSS やフォントも入らないので、必要なものはこの中で用意します。
置かなかったときは、実機では Next.js の既定の画面が出ました。英語で「This page couldn't load」と、エラーの番号だけが表示されます。
例外にしないほうがよいもの
公式ドキュメントは、起こりうると分かっている失敗(入力の誤りなど)は例外として投げず、値として返して画面に出すよう勧めています。error.tsx は、想定していなかった失敗の最後の受け皿です。
また公式ドキュメントによると、ボタンを押したときの処理(イベントハンドラ)の中で起きた例外は、error.tsx では受け止められません。描いている最中の例外だけが対象です。イベントハンドラの中では自分で try で受けて、画面に出します。
見つからないページは、例外ではなく notFound() で not-found.tsx を出します(見つからないときの最小構成)。
出す前に確かめること
- 本番と同じビルドで、わざと例外を投げて、エラー画面が出るかを見る
- 画面の
digestと、サーバーのログのdigestが同じ番号かを見る - ルートの layout でデータを読んでいるなら、
global-error.tsxがあるかを見る
出典
- nextjs.org/docs/app/api-reference/file-conventions/error
- nextjs.org/docs/app/getting-started/error-handling
このページの内容は上記の一次情報を基準に書いています。個人ブログや二次情報を根拠にしていません。