はじめに
ローカルで画像、動画のアップロードが成功したのですが本番では
An unexpected response was received from the server.
というエラーが発生して解決したことをまとめます。
問題
本番環境で画像/動画をServer Action経由でアップロード時に
413 Content Too Largeというエラーが発生した
ログを確認したところ、バックエンドのログにエラーログが発生していなかったため、フロント側に原因があると推測した。
いろんなパターンを試してみた
ファイル、動画、画像を送ることができる機能だったため、それぞれ試してみた
- 画像は複数送れる
- ファイルも送れる
- 単体なら送れる動画もあるが殆どの場合で動画が送れない
- 動画は複数送れない
- データのサイズに問題があるのではないかとログと実際の挙動から推測
- バリデーションはかかっており、巨大なサイズのものが送信前の段階でエラーを出力できていることが確認できた
next.config.tsの設定
公式で以下のように書かれていたため、bodySizeLimit, ``を追加
experimental: {
serverActions: {
bodySizeLimit: "30mb",
},
},
これを設定しても本番環境で問題解決できなかった
真の原因はServer Actionで実行していたことだった
答えはVercelの公式ドキュメントに記載してありました
なぜ next.configの設定は効かなかったのか
-
bodySizeLimit: Next.js自体のServer Actions制限(ローカル開発では有効) -
middlewareClientMaxBodySize: Next.js Middleware経由の制限
Vercel Fuctionには独自の制限があって、これをnext.configでは変更できない。Vercelのインフラレベルの制限のため、アプリ側の設定では回避不可能。
Vercel Functionとは?
- API Routes
- Server Action
- Route Handlers
これらなどが、デプロイ時にVercel上で実行されるサーバーレス関数のこと
なぜローカルではアップロードが成功したのか
結論、Vercelを経由せずにアップロードしていたから。
ローカル、本番の実際のデータの流れは以下です!
■ ローカル開発環境(✅ 成功)
[ブラウザ]
↓ POST /upload/xxx (10MBファイル)
[Next.js Dev Server] ← bodySizeLimit: "30mb" が有効
↓
[APIサーバー]
↓
[AWS S3] ✅ アップロード成功
■ 本番環境 - Vercel(❌ 失敗)
[ブラウザ]
↓ POST /upload/xxx (10MBファイル)
[Vercel Function] ← 4.5MB ハードリミット
✕ 413 FUNCTION_PAYLOAD_TOO_LARGE
[APIサーバー] ← 到達しない
[AWS S3]
解決方法
Vercel Function の 4.5MB 制限を回避するには、
Vercel Function を経由しないアーキテクチャに変更する必要があります。
方法1: クライアントからAPIサーバーへ直接送信
ブラウザ → APIサーバー → S3
Next.js の Server Actions を使わず、
外部のAPIサーバーに直接ファイルを送信する方式。
方法2: クライアントから直接ストレージへアップロード
ブラウザ → S3(署名付きURL経由)
Presigned URL を使い、ブラウザからS3等に直接アップロードする方式。
Vercel Blob などのサービスもこの方式を推奨しています。
まとめ
- Vercel Function(Server Actions含む)には 4.5MB のハードリミット がある
-
next.config.tsのbodySizeLimit設定は ローカルでのみ有効、Vercel上では無視される - 解決するには Vercel Function を経由しないアーキテクチャ に変更が必要
- クライアント → APIサーバーへ直接送信
- クライアント → ストレージへ直接アップロード(署名付きURL)