# 機能設計書 16-エラーハンドリング

## 概要

本ドキュメントは、Next.js App Routerにおけるエラーハンドリング機能の設計を記述する。error.tsxによるルートレベルのエラーバウンダリ機能であり、エラー発生時のフォールバックUIを提供する。React Error Boundaryと統合される。

### 本機能の処理概要

エラーハンドリング機能は、App Routerのルートセグメント単位でエラーバウンダリを定義し、レンダリングエラー発生時のフォールバックUIと回復機能を提供する。

**業務上の目的・背景**：Webアプリケーションでは、予期しないエラーが発生した場合にアプリケーション全体が使用不能になることを防ぐ必要がある。error.tsxファイルを配置するだけで、そのルートセグメントとその子孫にReact Error Boundaryが自動的に設定され、エラーの影響範囲を限定しつつ回復手段を提供する。

**機能の利用シーン**：サーバーコンポーネント/クライアントコンポーネントのレンダリングエラー、データフェッチエラー、予期しない例外、404/403/401等のHTTPアクセスエラーの表示で利用される。

**主要な処理内容**：
1. `error.tsx` ファイルの検出とLoaderTreeへの組み込み
2. ErrorBoundaryHandlerクラスコンポーネントによるReact Error Boundary構築
3. getDerivedStateFromErrorでのエラーキャプチャとNext.jsルーターエラーの再throw
4. エラーコンポーネントのレンダリングとreset関数の提供
5. パス変更時のエラーステート自動リセット
6. ボットリクエスト時の特殊処理（エラーバウンダリをバイパスして子をレンダリング継続）
7. ISRエラー時のHandleISRError連携

**関連システム・外部連携**：React Error Boundary、ISR再検証、HTTPアクセスフォールバック。

**権限による制御**：forbidden()（403）、unauthorized()（401）によるアクセス制御エラーとの統合。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 4 | グローバル404ページ (Global Not Found) | 主機能 | ルートレベルで一致するページが存在しない場合の404エラー表示処理 |
| 5 | 404ページ (Not Found) | 主機能 | セグメントレベルでのページ未発見時の404エラーフォールバック表示 |
| 6 | グローバルエラーページ (Global Error) | 主機能 | アプリケーション全体のキャッチされなかったエラーの表示処理 |
| 7 | 500エラーページ (App Error) | 主機能 | ビルド時に生成される静的500エラーページの表示処理 |
| 8 | 403ページ (Forbidden) | 主機能 | アクセス権限なし時の403エラーフォールバック表示 |
| 9 | 401ページ (Unauthorized) | 主機能 | 未認証ユーザーへの401エラーフォールバック表示 |

## 機能種別

エラー制御 / UI表示制御

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| error | Error | Yes | キャッチされたエラーオブジェクト | - |
| reset | () => void | No | エラーステートをリセットしてリトライする関数 | global-errorにはなし |

### 入力データソース

- Reactレンダリングフェーズで発生したエラー（getDerivedStateFromError経由）
- ファイルシステム（`app/**/error.tsx`、`app/global-error.tsx`）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| エラーUI | ReactNode | エラーコンポーネントのレンダリング結果 |
| errorStyles | ReactNode | エラーコンポーネント関連のスタイル |
| errorScripts | ReactNode | エラーコンポーネント関連のスクリプト |

### 出力先

- クライアントサイドDOM（エラー発生セグメントの表示）
- global-error.tsxの場合はアプリケーション全体

## 処理フロー

### 処理シーケンス

```
1. サーバーサイド: LoaderTreeからerrorモジュールの取得
   └─ parseLoaderTreeでmodules.errorを抽出
2. サーバーサイド: ErrorComponentとアセットの解決
   └─ createComponentStylesAndScriptsでCSS/JSを収集
3. クライアントサイド: ErrorBoundary関数コンポーネント
   └─ errorComponent存在時にErrorBoundaryHandlerでラップ
4. エラー発生時: getDerivedStateFromError
   └─ Next.jsルーターエラーは再throw、それ以外はstate更新
5. エラー表示: ErrorBoundaryHandler.render
   └─ HandleISRError + errorStyles/errorScripts + errorComponent
6. パス変更時: getDerivedStateFromProps
   └─ パスが変わった場合にエラーステートを自動リセット
7. リセット: reset関数
   └─ ユーザーによるエラーステートのクリア
```

### フローチャート

```mermaid
flowchart TD
    A[コンポーネントレンダリング] --> B{エラー発生?}
    B -->|No| C[正常表示]
    B -->|Yes| D[getDerivedStateFromError]
    D --> E{Next.jsルーターエラー?}
    E -->|Yes| F[エラーを再throw]
    E -->|No| G{ボットリクエスト?}
    G -->|Yes| H[children表示継続 + ISRエラー処理]
    G -->|No| I[errorComponent表示]
    I --> J{パス変更?}
    J -->|Yes| K[エラーステート自動リセット]
    J -->|No| L{ユーザーがreset?}
    L -->|Yes| K
    L -->|No| M[エラー表示継続]
    K --> A
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | ルーターエラー再throw | Next.jsルーターエラー（redirect/notFound等）はError Boundaryで捕捉せず親に再throw | ルーターエラー発生時 |
| BR-02 | パス変更リセット | ナビゲーションで別パスに移動するとエラーステートが自動リセット | パス変更時 |
| BR-03 | ボットバイパス | ボットリクエスト時はError Boundaryをバイパスしてchildren表示を継続 | ボットUA検出時 |
| BR-04 | セグメント限定 | error.tsxは同じセグメントのpage.tsxのエラーをキャッチするが、同じセグメントのlayout.tsxのエラーはキャッチしない | 常時 |
| BR-05 | global-error | app/global-error.tsxはルートレイアウトのエラーを含むすべてのエラーをキャッチ | ルートレベル |
| BR-06 | ハードナビゲーションフォールバック | ナビゲーション中のエラーはハードナビゲーションにフォールバック | __NEXT_APP_NAV_FAIL_HANDLING有効時 |

### 計算ロジック

該当なし。

## データベース操作仕様

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | レンダリングエラー | コンポーネント内の例外 | error.tsxのフォールバック表示 |
| 404 | Not Found | notFound()呼び出し | not-found.tsxの表示 |
| 403 | Forbidden | forbidden()呼び出し | forbidden.tsxの表示 |
| 401 | Unauthorized | unauthorized()呼び出し | unauthorized.tsxの表示 |
| - | Redirect | redirect()呼び出し | リダイレクトエラーとして再throw |

### リトライ仕様

reset()関数を呼ぶことで、エラーステートをクリアしてコンポーネントの再レンダリングを試行できる。

## トランザクション仕様

該当なし。

## パフォーマンス要件

- error.tsxはClient Componentである必要がある（'use client'ディレクティブ）
- Error Boundaryのセットアップ自体にパフォーマンスオーバーヘッドは最小

## セキュリティ考慮事項

- エラーメッセージにはサーバーサイドの機密情報を含めないよう注意が必要
- プロダクション環境ではエラーのスタックトレースがクライアントに公開されないようにする

## 備考

- error.tsxは必ずClient Component（'use client'）として定義する必要がある
- global-error.tsxはhtml/bodyタグを自身で定義する必要がある（ルートレイアウトの代替）
- HandleISRErrorコンポーネントがISRエラー時の再検証処理を担当する

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | error-boundary.tsx | `packages/next/src/client/components/error-boundary.tsx` | ErrorComponent型（13-18行目）、ErrorBoundaryProps（20-25行目）の定義を理解 |

**読解のコツ**: ErrorComponentはerror propとオプショナルなreset propを受け取る。global-errorではresetが提供されない。

#### Step 2: サーバーサイドのエラーコンポーネント解決

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | create-component-tree.tsx | `packages/next/src/server/app-render/create-component-tree.tsx` | errorモジュールの解決（174-182行目） |

**主要処理フロー**:
1. **139-147行目**: modules.errorの抽出
2. **174-182行目**: createComponentStylesAndScriptsでErrorComponent/errorStyles/errorScriptsの解決

#### Step 3: クライアントサイドのError Boundary

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | error-boundary.tsx | `packages/next/src/client/components/error-boundary.tsx` | ErrorBoundaryHandler（37-118行目）のクラスコンポーネント実装を理解 |
| 3-2 | error-boundary.tsx | `packages/next/src/client/components/error-boundary.tsx` | ErrorBoundary関数コンポーネント（129-156行目）でラップ判定を理解 |

**主要処理フロー**:
- **46-54行目**: getDerivedStateFromErrorでルーターエラーを再throw、その他をキャプチャ
- **56-92行目**: getDerivedStateFromPropsでパス変更時のエラーリセット
- **66-74行目**: ハードナビゲーションフォールバック処理
- **94-96行目**: reset関数の定義
- **99-117行目**: render()でエラー表示（ボット判定含む）
- **102行目**: isBotUserAgent判定でボット時のバイパス

#### Step 4: HTTPアクセスフォールバック

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | http-access-fallback.ts | `packages/next/src/client/components/http-access-fallback/http-access-fallback.ts` | 404/403/401エラーの判定と変換ロジック |
| 4-2 | error-boundary.tsx | `packages/next/src/client/components/http-access-fallback/error-boundary.tsx` | HTTPAccessFallbackBoundaryの実装 |

### プログラム呼び出し階層図

```
createComponentTreeInternal (create-component-tree.tsx)
    |
    +-- parseLoaderTree
    |      └─ modules.error の抽出
    |
    +-- createComponentStylesAndScripts (error用)
           └─ [ErrorComponent, errorStyles, errorScripts]

クライアントサイド:
OuterLayoutRouter (layout-router.tsx)
    |
    +-- ErrorBoundary (error-boundary.tsx)
           |
           +-- ErrorBoundaryHandler
           |      |
           |      +-- getDerivedStateFromError
           |      |      └─ isNextRouterError → 再throw
           |      |      └─ それ以外 → state更新
           |      |
           |      +-- getDerivedStateFromProps
           |      |      └─ パス変更検出 → エラーリセット
           |      |
           |      +-- render()
           |             └─ HandleISRError
           |             └─ errorComponent(error, reset)
           |
           +-- RedirectBoundary
           +-- HTTPAccessFallbackBoundary
```

### データフロー図

```
[入力]                       [処理]                        [出力]

error.tsx ------------> parseLoaderTree -------> ErrorComponent
                                                     |
Reactレンダリングエラー -> getDerivedStateFromError -> state.error
                                                     |
pathname変更 ---------> getDerivedStateFromProps -> state.error = null
                                                     |
reset()呼び出し ------> setState({error: null}) -> 再レンダリング
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| error-boundary.tsx | `packages/next/src/client/components/error-boundary.tsx` | ソース | ErrorBoundaryHandler/ErrorBoundary |
| create-component-tree.tsx | `packages/next/src/server/app-render/create-component-tree.tsx` | ソース | errorモジュール解決 |
| is-next-router-error.ts | `packages/next/src/client/components/is-next-router-error.ts` | ソース | ルーターエラー判定 |
| nav-failure-handler.ts | `packages/next/src/client/components/nav-failure-handler.ts` | ソース | ハードナビゲーションフォールバック |
| handle-isr-error.tsx | `packages/next/src/client/components/handle-isr-error.tsx` | ソース | ISRエラー処理 |
| http-access-fallback.ts | `packages/next/src/client/components/http-access-fallback/http-access-fallback.ts` | ソース | HTTPアクセスエラー判定 |
| redirect-boundary.tsx | `packages/next/src/client/components/redirect-boundary.tsx` | ソース | リダイレクトバウンダリ |
| navigation-untracked.ts | `packages/next/src/client/components/navigation-untracked.ts` | ソース | パス追跡（エラーリセット用） |
