VercelでdeploymentがReadyなのに404なら、まず同じdeploymentのURLと問題のpathを固定します。Readyはbuildとdeployment作成の成功であり、要求したrouteが正しく応答することまでは保証しません。すぐに全pathをindex.htmlへrewriteせず、出力がないのか、routeに届かないのか、アプリが404を返したのかを分けます。
本稿はVercel上の404診断です。対象projectへのアクセス、build・deployment・DNS・設定変更は実施していません。例は架空で、読者の環境に同じ原因があるという意味ではありません。
目次
URL・path・状態・error codeをそろえる
Team、project、deployment ID、commit、environment、URL、HTTP methodとpathを記録します。custom domainとdeployment固有のvercel.app URLを、同じpathで比べます。過去deploymentのURLと現在のdomainを比較していないかも確認します。
表は横にスクロールできます
| 症状 | 最初に調べる場所 | 避ける推測 |
|---|---|---|
| 固有URLは正常、domainだけ404 | domainとproject/deploymentの対応 | codeが必ず壊れた |
| 両方で全routeが404 | build出力とframework設定 | DNSだけが原因 |
| rootだけ404 | root routeとindexの出力 | 全siteが未deployment |
| SPA内の直接アクセスだけ404 | client/server routingの境界 | 全frameworkへ同じrewrite |
| 特定のdynamic routeだけ404 | param・生成対象・handler | globalなfallback追加 |
Vercelの404解説(新しいタブで開く)は、build後の出力とrouting metadataを分けて調べる方法を案内しています。domainだけ違う場合も、DNSを変更する前に、同じproject・同じpathを比較したか、host依存のroutingやdomain割当を確認します。
Outputで、期待する出力があるかを見る
deployment detailsのOutputとbuild logで、必要な静的ファイルやFunctionが生成されたかを確認します。ローカル開発サーバーで見えるrouteが、production buildにも含まれるとは限りません。出力がなければ、先にRoot Directory、Framework Preset、build command、Output Directoryを照合します。
monorepoなら対象appのrootとpackage/build設定を確認します。repository root、app root、生成物directoryは同じとは限りません。Next.js等のframework固有出力と、汎用静的siteのdistを取り違えないようにします。設定名を見て適当にoutやdistを指定せず、実際に生成された出力と対象frameworkの公式方式へ合わせます。
一般的な静的siteでrootだけ404なら、index.html相当の入口が出力されたかを見ます。一方、サーバー frameworkのroutingを、ファイル名だけで判断しません。生成物があるのに404なら、その時点でrouting側を調べます。
アプリへ届いた404かを確認する
Functionの呼出があるか、該当時刻・deployment・pathのruntime logを見ます。アプリのhandlerが起動して自らnot foundを返したなら、ID、検索条件、対象データ、環境差などのアプリ側診断へ進みます。handler前で止まるなら、rewrite、redirect、middleware、route定義を調べます。
logが見つからない場合、検索期間、対象environment、保持期間、filterが正しいかも確認します。静的routeにはFunctionの呼出が不要なので、logがないという理由だけで失敗にしません。機密値や個人情報を詳細logへ追加せず、requestの識別情報と状態で絞ります。
NOT_FOUNDの公式説明(新しいタブで開く)と画面のerror codeを照合します。DEPLOYMENT_NOT_FOUNDのようにdeploymentの存在やURLが関係する場合を、アプリの一件のrecordがない404と同じ修正にしないようにします。
SPA fallbackとframework routingを混ぜない
SPAの画面内遷移は成功し、同じURLのreloadだけ404なら、サーバー側がそのpathをどう解決するかを確認します。必要なfallbackは対象のSPAとdeploy方式に合わせます。APIやassetまで一括でindexへ送る設定にすると、APIがHTMLを200で返す別の障害を作る場合があります。
Next.jsなど独自のroutingを持つframeworkへ、SPA用catch-allをそのまま追加しません。既存のframework設定とvercel.json、middleware等の重複を読み、最初にどの規則が該当するかを確認します。dynamic routeでは、そのparamが静的生成の対象か、動的に処理する設計かを、そのバージョンのframework資料で確認します。
最小の差分で再確認し、結果を引き継ぐ
変更前の設定、問題URL、比較した正常route、deploymentを保存します。許可された検証環境で原因に対応する一つの差分だけを試し、必要な再buildを含む運用手順で確認します。本稿でその操作を行ったという意味ではありません。
表は横にスクロールできます
| 受入確認 | 合格とする結果 | 残る問題の例 |
|---|---|---|
| rootと通常route | 期待する内容と状態 | rootだけ直った |
| 直接アクセス・reload | 同じ画面へ到達 | client遷移のみ成功 |
| API・asset | 本来の型と内容 | HTML fallbackの巻込み |
| 存在しないroute | 意図した404 | すべて200で隠す |
| domain | 意図したdeploymentとpath | 別バージョンへ接続 |
失敗したら、今回の設定差分を戻し、別の原因候補を証拠から選び直します。domainの切替や本番deploymentは、診断とは別の運用判断です。完了記録は「Readyになった」だけでなく、どのURL・path・内容が回復し、どこを未確認にしたかまで残します。
