# Vercel トラブルシューティング大全：ビルド失敗・関数エラー・504/413・404・コールドスタートを原因別に潰す

> Vercelの本番でよく出るエラーを原因別に解決する実践ガイド。FUNCTION_INVOCATION_TIMEOUT(504)・FUNCTION_PAYLOAD_TOO_LARGE(413)・FALLBACK_BODY_TOO_LARGE、ビルド失敗（出力ディレクトリ/ビルドスクリプト/関数パターン/設定衝突）、動的ルートの404、環境変数が効かない、コールドスタート、Edge Config接続エラーまで、公式準拠の原因と修正手順を実コードで解説します。

- 公開日: 2026-06-28
- 著者: 友田 陽大
- タグ: Vercel, Next.js, 可観測性, インフラ, CI/CD, TypeScript, パフォーマンス
- URL: https://tomodahinata.com/blog/vercel-troubleshooting-build-function-errors-timeout-guide
- カテゴリ: Vercel 本番運用
- 総合ガイド: https://tomodahinata.com/blog/vercel-production-platform-guide

## 要点

- Vercelのエラーは『関数・デプロイ/ビルド・ルーティング・リクエスト・設定』のカテゴリに分けて原因を絞る。まずObservabilityとRuntime Logsで症状を特定し、エラーコードから逆引きする
- FUNCTION_INVOCATION_TIMEOUT(504)はmaxDuration超過。長時間処理はWorkflows/キューへ分離し、ストリーミングで初動を返す。既定300秒・Pro/Ent最大800秒を理解する
- FUNCTION_PAYLOAD_TOO_LARGE(413)はリクエスト/レスポンス本文4.5MB超。アップロードはclient uploadでBlobへ直送し関数を経由しない。FALLBACK_BODY_TOO_LARGEはISRページ20MB超で、ページ生成物を軽くする
- ビルド失敗の頻出は『出力ディレクトリ/ビルドスクリプトの誤り』『関数パターン不一致（apiディレクトリ外）』『functionsとbuildsの設定衝突』『ルートのpath-to-regexp構文ミス』。ローカルで同じビルドコマンドを再現して切り分ける
- 環境変数の変更は新しいデプロイにのみ反映される（既存は変わらない）。NEXT_PUBLIC_でないとブラウザに出ない。動的ルートの404はgenerateStaticParamsとdynamic設定、カスタムドメインのDNSを確認する

---

本番で 504 や 413、ビルド失敗が出ると焦ります。けれど Vercel のエラーは**カテゴリと原因がほぼ決まっている**ので、逆引きで素早く潰せます。この記事は、[Vercel 公式のエラー一覧](https://vercel.com/docs/errors)と[Functions の制限](https://vercel.com/docs/functions/limitations)に忠実に、**現場で本当に出るエラーを原因別**にまとめた実践集です。

全体像は [Vercel 本番運用ガイド](/blog/vercel-production-platform-guide) を参照してください。

---

## まず：症状を特定する（推測しない）

エラーコードを見たら、闇雲に直す前に**ログで一次情報**を取ります。

1. **Observability タブ**：どのルートがエラー率・遅延を上げているか特定（[可観測性](/blog/vercel-observability-monitoring-speed-insights-log-drains-guide)）。
2. **Runtime Logs**：該当関数のログ・スタックトレースを確認。
3. **Build Logs**：ビルド失敗はここに全部出る。
4. **`x-vercel-cache` / レスポンスヘッダ**：キャッシュ・ルーティングの状態。

エラーは大きく**5カテゴリ**です。

| カテゴリ | 代表コード | 出る場所 |
|---|---|---|
| 関数 | `FUNCTION_INVOCATION_TIMEOUT`(504), `FUNCTION_PAYLOAD_TOO_LARGE`(413), `FUNCTION_INVOCATION_FAILED`(500) | 実行時 |
| デプロイ/ビルド | Missing public directory, Missing build script, `FALLBACK_BODY_TOO_LARGE` | ビルド時 |
| ルーティング | 動的ルートの404, Invalid route source pattern | リクエスト時 |
| リクエスト | ボディ超過, 認証/保護 | 入口 |
| 設定 | functions vs builds 衝突, Edge Config 接続文字列無効 | デプロイ時 |

---

## 関数エラー

### FUNCTION_INVOCATION_TIMEOUT（504）

**原因**：関数が `maxDuration`（既定300秒、Pro/Ent 最大800秒）以内に完了しなかった。長い同期処理・無限待ち・外部APIのハングが典型。

**修正**：

```ts
// ① まず maxDuration を用途に合わせて明示（だらだら生かさない）
export const maxDuration = 60;

// ② 長時間処理は関数に抱えず Workflows / キューへ分離
//    （数分を超える処理を同期HTTPで持たない）
export async function POST(request: Request) {
  const job = await enqueueHeavyJob(await request.json()); // すぐ返す
  return Response.json({ jobId: job.id }, { status: 202 });
}

// ③ 進捗を返したいならストリーミングで初動を速く
```

外部 API 呼び出しには**タイムアウトと AbortController** を付け、ハングを自分で切ります。重い処理の分離は [Functions ガイド](/blog/vercel-functions-fluid-compute-streaming-cron-guide) を参照。

### FUNCTION_PAYLOAD_TOO_LARGE（413）

**原因**：リクエスト本文またはレスポンス本文が **4.5MB** を超えた。ファイルアップロードを関数で受けているのが典型。

**修正**：アップロードは**関数を経由せず** Vercel Blob へ**直送（client upload）**します。

```ts
// 旧：関数で multipart を受ける → 4.5MB で死ぬ
// 新：client upload でブラウザから Blob へ直接（転送課金も回避）
import { upload } from "@vercel/blob/client";
const blob = await upload(file.name, file, {
  access: "public",
  handleUploadUrl: "/api/upload", // トークン発行＋認可だけサーバーで
});
```

詳細は [ストレージ・Blob ガイド](/blog/vercel-storage-blob-edge-config-marketplace-guide)。レスポンスが大きい場合は、ページング・ストリーミング・Blob 経由の配信に変えます。

### FALLBACK_BODY_TOO_LARGE（ISRページが大きすぎる）

**原因**：ISR / プリレンダーのレスポンスが **20MB** を超えると、本番でページが描画されない。巨大な埋め込みデータ・画像inline・冗長な JSON が原因。

**修正**：ページ生成物を軽くする。データは分割取得・遅延ロード、画像は [next/image](/blog/vercel-image-optimization-next-image-cost-performance-guide) で外出し、不要な inline JSON を削る。

### FUNCTION_INVOCATION_FAILED（500）

**原因**：関数内で未捕捉の例外。DB 接続失敗、env 未設定、null 参照など。

**修正**：Runtime Logs でスタックトレースを確認。境界で例外を捕まえ、500 ではなく**意味のあるエラー**を返す。env 未設定が多いので、起動時に必須 env を [Zod で検証](/blog/nextjs-env-secret-leak-prevention-public-vars-guide)。

---

## ビルド失敗

ビルド失敗は **Build Logs に原因がすべて出ます**。頻出を原因別に。

### 出力ディレクトリ／ビルドスクリプトの誤り

> Missing public directory / Missing build script

**原因**：出力ディレクトリが間違っている、`build` スクリプトがない、ルートディレクトリ（モノレポ）の指定ミス。

**修正**：

- Project Settings の **Output Directory / Build Command / Root Directory** を確認。
- **ローカルで同じビルドコマンドを実行**し、出力先に成果物が生成されるか確認（最速の切り分け）。
- モノレポは Root Directory をアプリのパスに設定。

### 関数パターン不一致 / 設定の衝突

> Unmatched function pattern / Conflicting functions and builds

**原因**：`vercel.json` の `functions` グロブが `api/` 配下のファイルに一致していない、または `functions` と `builds` を**併用**している（併用不可）。

**修正**：

```json
// ❌ api/ 外を指している
{ "functions": { "users/**/*.js": { "maxDuration": 30 } } }

// ✅ api/ 配下を指す（Next.js は pages/api/** も可）
{ "functions": { "api/users/**/*.js": { "maxDuration": 30 } } }
```

`functions` と `builds` はどちらか一方のみ。原則 `functions`（メモリ設定等が可能）を使います。Next.js では `functions` で設定できるのは `memory` と `maxDuration` だけ（他は Next.js が自動管理）。

### ルートの構文ミス

> Invalid route source pattern

**原因**：`vercel.json` の `source`/`rewrites`/`redirects` は **path-to-regexp** 構文で、生の正規表現ではない。否定先読みはグループで包む必要がある。

```json
// ❌ "source": "/feedback/(?!general)"
// ✅ "source": "/feedback/((?!general).*)"
```

### 依存・パッケージマネージャの不整合

**原因**：`ERR_PNPM_UNSUPPORTED_ENGINE`（`engines.pnpm` 不一致）、lockfile とパッケージマネージャの食い違い、Node バージョン差。

**修正**：`package.json` の `engines`/`packageManager` を合わせる、または Corepack を有効化。Node は **24 LTS が既定**（18 は非推奨）。`@vercel/speed-insights`/`@vercel/analytics` は**グローバルではなく `package.json` の依存**に入れる（モノレポで頻発）。

---

## ルーティングと 404

### 動的ルートが 404 になる

**原因**：`generateStaticParams` が対象を返していない、`dynamic`/`dynamicParams` 設定、ビルド時に存在しないパス。

**修正**：

```ts
// 事前生成しないパスもオンデマンドで通す
export const dynamicParams = true; // 既定 true（false だと未生成は404）

export async function generateStaticParams() {
  // 少なくとも代表パスを返す。残りはオンデマンド生成（ISR）
  return (await getPopularSlugs()).map((slug) => ({ slug }));
}
```

ISR の挙動は [キャッシュ・ISR ガイド](/blog/vercel-caching-isr-cache-components-ppr-guide)。

### カスタムドメインで表示されない / DNS

**原因**：DNS レコード（A/CNAME）未設定・伝播待ち、ドメイン未追加。

**修正**：`vercel domains inspect <domain>` で必要なレコードを確認。TTL を短くしておくと切替・確認が速い。

---

## 環境変数が「効かない」

これは**エラーではなくハマりどころ**で、相談が非常に多い。

- **環境変数の変更は新しいデプロイにのみ反映**される。既存の本番デプロイは変わらない → **再デプロイ**する。
- ブラウザ（クライアント）で読むには **`NEXT_PUBLIC_` 接頭辞**が必要。逆に機密は付けてはいけない。
- 環境（production/preview/development）ごとに値を設定する。プレビューで未設定だとプレビューだけ落ちる。
- Edge Config の接続文字列無効（`Invalid Edge Config connection string`）は、`EDGE_CONFIG` env が古い/削除済み → 更新。

詳細は [環境変数・シークレット ガイド](/blog/vercel-environment-variables-secrets-oidc-management-guide)。

---

## コールドスタート・遅い

**原因**：関数の初期化が重い（大きな依存・起動時の重処理）、キャッシュ未ヒットで毎回関数実行。

**修正**：

- **Fluid Compute**（既定）で並行性とプリウォーム、Node 20+ のバイトコードキャッシュが効く。
- 起動時の重処理（大きな JSON パース・接続確立）をハンドラ外で一度だけ・遅延化。
- **そもそも関数を呼ばない**——ISR/CDN キャッシュで `HIT` にする（[キャッシュ](/blog/vercel-caching-isr-cache-components-ppr-guide)）。`x-vercel-cache` で確認。
- バンドルを削る（不要依存の除去、250MB 上限）。

---

## トラブル切り分けチェックリスト

- [ ] **Observability / Runtime Logs / Build Logs** で一次情報を取った（推測しない）
- [ ] 504 → `maxDuration` 明示 ＋ 長時間処理を**分離**、外部APIにタイムアウト
- [ ] 413 → アップロードは **client upload で Blob 直送**
- [ ] ISR 20MB 超 → ページ生成物を軽量化
- [ ] ビルド失敗 → **ローカルで同じビルドを再現**、出力先/ルート/関数パターン確認
- [ ] 404 → `generateStaticParams`/`dynamicParams`、DNS
- [ ] env が効かない → **再デプロイ**、`NEXT_PUBLIC_`、環境ごとの設定
- [ ] 遅い → キャッシュで `HIT`、Fluid、バンドル削減

---

## まとめ

Vercel のトラブルシュートは「**症状をログで特定 → カテゴリ → 原因 → 定石の修正**」で機械的に潰せます。

1. **推測せずログ**（Observability / Runtime / Build Logs）
2. **504 は分離、413 は Blob 直送、ISR 20MB は軽量化**
3. **ビルド失敗はローカル再現**で切り分け
4. **env は再デプロイ・`NEXT_PUBLIC_`・環境別設定**
5. **遅さはキャッシュ HIT**で根治

本番の障害調査・恒久対策・再発防止の作り込みまで、案件として伴走します。「原因不明の 504/500 が出ている」段階からのスポット調査も承ります。

> 本記事は [Vercel エラー一覧](https://vercel.com/docs/errors) / [Functions 制限](https://vercel.com/docs/functions/limitations) 公式ドキュメント（2026年6月時点）に基づきます。エラーコード・上限は更新されるため、最新は公式で確認してください。
