本文へ移動
verified onnext@16.3.5react@19
最終検証日 2026-09-26
Next.js道場

Next.js の 404 とエラー画面。最小構成サンプル

うまくいかない形は2つあります。

動いているものを触る/demo/notfound

ファイル構成

並んでいるのは、上の画面をいま動かしている本物のファイルです。名前を押すと中身が出ます。

ファイル構成
  • app/
  • [id]/
app/layout.tsxBuild

全ページの外側。本物のプロジェクトでは html と body をここで書きます

import type { Metadata } from "next";
 
export const metadata: Metadata = {
  title: "404 とエラーの最小構成",
};
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return <main>{children}</main>;
}
.tsx
画面を返すファイル。HTML のような書き方ができます
.ts
画面を返さないファイル。処理とデータだけを置きます。ここに画面を書くと原因を名指ししないエラーで落ちます
Build
ビルド時に一度だけ動きます
Server
アクセスのたびにサーバーで動きます
Browser
利用者の手元で動きます

「無い」と「壊れた」は別のこと

うまくいかない形は2つ。置くファイルも、必要なものも違う
どんなとき置くファイルuse client
探したが無かったnot-found.tsxできない
途中で失敗したerror.tsxできる

同じ「うまくいかない」でも、利用者への意味がまったく違います。無いものは何度やっても無い。失敗はもう一度やれば通るかもしれない。だから片方には「もう一度」が要り、もう片方には要りません。

無いものは、無いと言う

const { id } = await params
if (id !== "ok") notFound()

notFound() を呼ぶと、Next.js が not-found.tsx を探して出します。自分で <NotFound /> を書く必要はありません。

実機で確かめました。/demo/notfound/zzz は HTTP 404 を返します。画面が404らしく見えるだけでなく、応答そのものが 404 です。

片方だけ use client が要る

同じ「うまくいかない」でも、必要なものが違う
not-found.tsx
// use client は要らない
export default function NotFound() {
  return <p>その id はありません。</p>
}

描くだけ。サーバー側のままでよい。

error.tsx
'use client'
 
export default function Error({ error, reset }) {
  return <button onClick={reset}>もう一度</button>
}

押せるものを持つ。書かないとビルドが落ちる。

失敗は、サーバーで起こさない

このサンプルの「わざと失敗させる」ボタンは、ブラウザ側で失敗しています。

'use client'
 
export function Boom() {
  const [broken, setBroken] = useState(false)
  if (broken) throw new Error('わざと失敗させています')
  ...
}

押すとどうなるか

実機で確かめた動きです。

押す前    2つの「うまくいかない」を見比べます …
押した後  うまくいきませんでした。 / もう一度
もう一度  2つの「うまくいかない」を見比べます …   ← 元に戻る

reset は、失敗した部分をもう一度描き直させる関数です。ページを開き直すのとは違い、そこだけをやり直します。

失敗してから、戻るまで
  1. Browser
    描いている途中で失敗する

    その部分から上へ、いちばん近い error.tsx が受け止める。

  2. Browser
    error.tsx が出る

    ページ全体は生きている。ヘッダーもフッターも残る。

  3. Browser
    もう一度を押す

    reset が呼ばれ、その部分だけ描き直される。

digest は、サーバーで失敗したときだけ

error.tsx が受け取る error には digest が付くことがあります。このサンプルでは出ません。ブラウザ側で失敗しているからです。

サーバー側で失敗したときは、本番ビルドでは例外の中身が届かず、番号だけが付きます。中身を知るにはサーバーのログを見ます。詳しくはServer Function の呼び方にあります。

ここから足していくとき

  • 記録する。どこで失敗したかをサーバーへ送ります。ただし利用者の入力は送らない
  • 案内を出す。「時間をおいて」なのか「問い合わせて」なのかで、書くことが変わります
  • 全体を覆う。app 直下の global-error.tsx は、レイアウトごと壊れたときに出ます

まず「無い」と「壊れた」を分けてください。分けずに1つの画面で済ませると、利用者は次に何をすればよいか分かりません。

入れていないもの

このまま本番に持っていかないでください。省いてあるのは次の点です。

  • 失敗の記録。どこで失敗したかをサーバーに残していません
  • 利用者への案内。問い合わせ先や再試行の回数を出していません
  • サーバー側で失敗させる入口。公開の画面に置くと、誰でもエラーを起こせます
  • 全体を覆う error。app 直下の global-error は置いていません

出典

このページの内容は上記の一次情報を基準に書いています。個人ブログや二次情報を根拠にしていません。

理解できたか試す

では、このコードはどうなりますか。

エラー画面を app/error.tsx に置きました。use client は書いていません。ビルドするとどうなりますか。

この問題を解くこのテーマの問題 3 問