エラーの概要
Vercelの502 Bad Gatewayエラーは、Edge Networkがバックエンド(サーバー側の処理)のOrigin(Serverless Functionまたはフレームワーク)から不正な応答を受け取った、またはタイムアウト(応答待機時間超過)が発生したことを示します。つまり、リクエスト(クライアントからの要求)はVercelのネットワークに到達しても、実際の処理を担当する関数やサーバーが期待通りの応答を返していない状況です。このエラーが発生すると、ユーザーには「502 Bad Gateway」というHTTPステータスコードが返され、アプリケーションの機能停止に直結します。
実際のエラーメッセージ例
ブラウザには以下のように表示されます:
502 Bad Gateway
Vercelダッシュボードのログ、または vercel logs コマンドでは:
{
"statusCode": 502,
"message": "Bad Gateway",
"details": "The server did not return a valid response"
}
また、関数のコンソール出力に以下のようなメッセージが表示される場合もあります:
FunctionError: Code execution timed out.
よくある原因と解決手順
原因1:Serverless Functionがレスポンスを返さずに終了している
Node.jsのServerless Functionでは、リクエストハンドラーが必ず response.send()、response.end()、またはreturn文でレスポンス(サーバーからの応答)を返す必要があります。これらが呼ばれずに関数が終了すると、Vercelは有効なレスポンスを受け取れず、502エラーが発生します。
Before(エラーが起きるコード):
export default function handler(req, res) {
const data = fetchData();
// レスポンスを返さずに関数が終了してしまう
console.log('処理完了');
}
After(修正後):
export default function handler(req, res) {
const data = fetchData();
res.status(200).json({
success: true,
data: data
});
}
別の例として、非同期処理の場合:
Before(エラーが起きるコード):
export default async function handler(req, res) {
// awaitがないため、Promiseの完了を待たずに進む
fetchDataAsync();
res.status(200).json({ message: 'OK' });
}
After(修正後):
export default async function handler(req, res) {
// 必ずawaitでPromiseの完了を待つ
const data = await fetchDataAsync();
res.status(200).json({ message: 'OK', data: data });
}
原因2:バックエンドのOriginサービスがクラッシュまたは不正な応答を返している
Next.jsのページ内でバックエンドAPI(サーバーのデータ提供機能)呼び出しを行う際、外部APIやデータベースが正常に応答していない、またはタイムアウトが発生している場合に502エラーが起こります。
Before(エラーが起きるコード):
export default async function handler(req, res) {
try {
// タイムアウト設定なしで無期限に待機してしまう
const response = await fetch('https://external-api.example.com/data');
const data = await response.json();
res.status(200).json(data);
} catch (error) {
// エラーハンドリングがなく、レスポンスが返されない
console.error(error);
}
}
After(修正後):
export default async function handler(req, res) {
try {
// タイムアウトを5秒に設定
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
const response = await fetch('https://external-api.example.com/data', {
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
return res.status(502).json({ error: 'External API error' });
}
const data = await response.json();
res.status(200).json(data);
} catch (error) {
console.error(error);
// 必ずエラーレスポンスを返す
res.status(502).json({ error: 'Internal server error' });
}
}
原因3:ビルド成果物が不完全またはデプロイが失敗している
vercel build または npm run build でビルドが正常に完了していない場合、実際のアプリケーションコードが本番環境に存在しないため、502エラーが発生します。
Before(エラーが起きるコード):
{
"buildCommand": "npm run build",
"outputDirectory": "wrong-directory"
}
After(修正後):
{
"buildCommand": "npm run build",
"outputDirectory": ".next",
"framework": "nextjs"
}
または package.json のbuildスクリプトに問題がないか確認:
Before(エラーが起きるコード):
{
"scripts": {
"build": "npm run lint && next build",
"lint": "exit 1"
}
}
After(修正後):
{
"scripts": {
"build": "next build",
"lint": "eslint ."
}
}
Vercel固有の注意点
Vercelでの502エラーは、環境によって表現が異なります。本番環境(Production)では即座にエラーページが返されますが、プレビュー環境(Preview)では関数のログが詳細に表示されることがあります。
Serverless Functionのタイムアウト設定:デフォルトでは最大30秒のタイムアウトが設定されています。より長い処理が必要な場合、Pro以上のプランであれば vercel.json でタイムアウト時間を延長できます:
{
"functions": {
"api/**": {
"memory": 3008,
"maxDuration": 60
}
}
}
Next.jsのAPIRoutesの場合:/pages/api/ ディレクトリ配下のファイルが正しくデプロイされているか、vercel inspect コマンドで確認できます。
ミドルウェアー層の確認:Next.jsの middleware.ts が大量のリソースを消費している場合、Serverless Functionの実行前に失敗することがあります。
それでも解決しない場合
ログの確認
vercel logs コマンドでリアルタイムログを確認します:
vercel logs <url> --follow
特定のプロダクションデプロイメントのログを見る場合:
vercel logs <your-production-url> --follow
ローカルテスト
vercel dev でローカル環境でVercelのシミュレーション環境を起動し、本番と同じ条件で動作確認を行います:
vercel dev
この際、ローカルでは動作するが本番で502が出ている場合、以下を確認してください:
- 環境変数が本番環境で正しく設定されているか(Vercelダッシュボードの Settings > Environment Variables)
- 関数のメモリー設定が不足していないか
- 外部APIのホワイトリスト設定に本番ドメインが含まれているか
公式ドキュメントの参照
免責事項:本記事の内容は、執筆時点の公開情報をもとに作成したものです。ソフトウェアの仕様は予告なく変更されることがあります。最新の情報は各ツールの公式サポートページをご確認ください。本記事の情報を利用した結果生じたいかなる損害についても、著者および運営者は責任を負いかねます。