反映されない時、Retry を押す前に見る3か所 — Cloudflare Pages の切り分け手順
この記事について
複数のサイトを1つのリポジトリで運用し、Cloudflare Pages で配信している。ある夜、記事をマージしたのに本番へ出ない状態が1時間ほど続いた。その間に再試行を2回、別々の間違った場所で実行している。
原因はどれも Cloudflare の故障ではなく、こちら側の読み違えだった。同じ読み違えを繰り返さないための手順書として残す。
| 読み違えた点 | 実際 |
|---|---|
| URL が 200 を返す=公開済み | catch-all があるサイトでは存在しないURLも 200 |
| プロジェクト名がサイト名と対応している | 対応していない。名前で選ぶと別サイトを操作する |
| 反映されない=再試行すべき | 待ち行列が渋滞しているだけなら、押すと遅くなる |
| API が認証エラー=トークンが失効 | 有効なまま権限だけ足りない場合も同じエラー |
検証環境は macOS / wrangler 4.85.0 / Astro 製サイト(Git 連携によるビルド)。確認日は2026年8月14日。
症状:URL は 200 を返すのに、記事が出ない
最初に踏んだ落とし穴がこれ。デプロイ確認のつもりで記事URLを叩き、200 が返ったので「公開済み」と判断した。
curl -o /dev/null -w "%{http_code}\n" https://example.com/journal/my-new-article/
# → 200
curl -o /dev/null -w "%{http_code}\n" https://example.com/journal/definitely-not-a-real-slug/
# → 200 ← 存在しないURLも同じ
_redirects の catch-all を持つサイトでは、存在しないパスもステータス 200 で応答する。ステータスコードは「サーバーが応答したか」しか示さない。
反映確認は中身で行う。記事一覧のHTMLに slug が現れるか、本文中の特徴的な文字列が含まれるかを見る。
curl -s https://example.com/journal/ | grep -c "my-new-article"
# 0 なら未反映。1以上なら反映済み
どのプロジェクトかを先に確定する
複数サイトを1リポジトリで運用していると、Cloudflare 側にもプロジェクトが複数できる。このときプロジェクト名がサイト名と一致している保証はまったくない。
実際、sites-aax と sites-6t3 という似た名前のプロジェクトがあり、前者と後者は無関係なサイトを配信していた。さらに紛らわしいことに、サイト名と同名のプロジェクトも別に存在したが、そちらは本番ドメインに接続されていなかった。
判定はプロジェクト画面上部の Domains: 行で行う。 目的のドメインが載っていなければ、そのプロジェクトを何度操作しても目的のサイトは動かない。
Status 列の3種類
一覧の Status 列に出る表示は、対処が三者三様になる。
| 表示 | 意味 | 対処 |
|---|---|---|
| ✓ 成功 | いま配信されている版 | 触らない |
| 🕐 待ち状態(Queued) | ビルドの順番待ち | 押さない。待てば出る |
| ▶▶ No deployment available | 新しいコミットに追い越されてスキップ | 正常。異常ではない |
| ✕ 失敗(Failed) | ビルドが落ちて古い版を配信し続けている | これだけが Retry の対象 |
「No deployment available」は文面が不穏だが故障ではない。古いコミットを作っても無駄なので飛ばした、という記録にすぎない。
待ちが並んでいるときに押してはいけない理由
Retry deployment は「このデプロイをもう一度ビルドする」操作であり、列に1件追加する。渋滞しているところに押せば、自分の順番はさらに後ろになる。
# キュー先頭のコミットに目的のファイルが入っているか
git cat-file -e <キューにあるsha>:path/to/article.md && echo "含まれる"
実際の事例では、待ち行列の先頭にあったコミットに目的の記事が入っていた。何も押さずに待った結果、約25分後に列が捌けて自動的に公開された。押していれば、その25分はもっと延びていた。
渋滞そのものは、深夜にプロジェクト数 × main への push 回数だけビルドが起きて同時実行の上限に当たったもの。恒常的な設定ミスではないので、対処は「待つ」でよい。
トークンが「失効した」ように見えるとき
コマンドラインから状況を見ようとして認証エラーが出た場合、失効と権限不足は同じエラーコードになる。ここを取り違えると、再発行という不要な作業に向かう。
切り分けは検証用エンドポイントで1秒で付く。
curl -s -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
https://api.cloudflare.com/client/v4/user/tokens/verify
# {"success":true,"result":{"status":"active"}} → 失効ではない=権限不足
active が返るなら、やることは再発行ではなく権限を1行足すこと。Permissions に Account / Cloudflare Pages / Edit を追加する。これは画面の道順ではなく、トークン作成画面にある3つのドロップダウンの値である(この2つを混同した説明をして、相手を混乱させた)。
権限が通れば、再試行もコマンドから実行できる。
curl -X POST -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
"https://api.cloudflare.com/client/v4/accounts/<account_id>/pages/projects/<project>/deployments/<deployment_id>/retry"
手順のまとめ
- ☑ 反映確認はステータスコードでなく中身で行う(catch-all は 200 を返す)
- ☑ プロジェクトは
Domains:行で特定する(名前は当てにならない) - ☑ Status が「待ち状態」なら押さない。キューのコミットに目的の変更が入っていないかを先に見る
- ☑ 「No deployment available」は正常。追い越されただけ
- ☑ Retry の対象は Failed だけ
- ☑ 認証エラーは
/user/tokens/verifyで失効と権限不足を分ける
この6行のうち5行は、実際に間違えてから書いている。特にプロジェクトの取り違えは、こちらが誤った案内を2回続けて出したもので、操作する人の時間を無駄にした。名前ではなくドメインで照合するという一手間を省いたことが原因だった。
なお、この記事の図はダッシュボードの実際のスクリーンショットではなく、同じ内容を再現した図である。管理画面のスクリーンショットにはアカウント固有の情報が写り込むため、公開する文書では再現図のほうが扱いやすい。