「アスタリスク事件」の後日談 — 自動化スクリプトが吐いた日付文字列でビルドが全滅した

  • #Astro
  • #YAML
  • #Python
  • #デバッグ
  • #自動化
  • #Cloudflare Pages
「アスタリスク事件」の後日談 — 自動化スクリプトが吐いた日付文字列でビルドが全滅した

この記事について

アスタリスク1個でサイトが11日間凍結した話 の後日談。前回の「skipped」問題は監視パスの設定で決着したが、しばらく後に今度はまったく別の原因でビルドが全滅した。今回は「skip」ではなく「Failure」だった。

原因も修正も単純だったが、自動化スクリプトがひっそり破壊していた経緯は記録しておく価値がある。


何が起きたか

7/4 以降、Cloudflare Pages の Production ビルドと Preview ビルドが全件 Failure になった。前回と違い、今回はエラーメッセージがあった。

InvalidContentEntryFrontmatterError

Astro のコンテンツコレクションが frontmatter のバリデーションに失敗している。


原因:YAML に吐き出された引用符付き日付文字列

promote_deploy_to_journal.py というスクリプトが、zashstudio の drafts を journal(Astro コンテンツコレクション)へ昇格させる工程で使われている。このスクリプトが frontmatter を生成するとき、Python の datetime.date.today().isoformat() を呼んで得た 文字列yaml.safe_dump に渡していた。

# 問題のあったコード
from datetime import date
frontmatter['date'] = date.today().isoformat()  # 文字列 '2026-07-04' を渡す
yaml.safe_dump(frontmatter)

yaml.safe_dump は文字列を受け取ると、YAML 上で引用符付きの文字列として出力する。

# 生成された frontmatter(問題あり)
date: '2026-07-04'

Astro の content schema は z.date() で定義されており、これは JavaScript の Date オブジェクトとして解釈できる値を要求する。'2026-07-04' という引用符付き文字列は YAML 上では文字列型であり、Astro が Date にパースできず InvalidContentEntryFrontmatterError になった。


前回との違い

観点前回(アスタリスク事件)今回
ビルド状態skipped(ビルド自体が走らない)Failure(ビルドが走ってエラー終了)
影響範囲全 push がデプロイされない7/4 以降に昇格した記事 2 本が未反映
犯人CF Pages のダッシュボード設定自動化スクリプトの日付型の渡し方
エラーメッセージなし(サイレント)InvalidContentEntryFrontmatterError(あり)

今回はエラーメッセージがあったため、前回より原因特定が速かった。


修正内容(PR #325)

3 点同時に対応した。

1. スクリプト側:date オブジェクトを直接渡す

isoformat() で文字列化せず、datetime.date オブジェクトを yaml.safe_dump にそのまま渡す。Python の PyYAML は datetime.date 型を受け取ると、引用符なしの date: 2026-07-04 として出力する。

# 修正後
from datetime import date
frontmatter['date'] = date.today()  # dateオブジェクトをそのまま渡す
yaml.safe_dump(frontmatter)
# 出力: date: 2026-07-04(引用符なし)

2. Astro スキーマ側:文字列日付も許容する(再発防止)

z.date() は厳格に Date 型しか受け付けない。スクリプト側を直しても、別のルートから文字列日付が紛れ込んだ場合に同じ問題が再発する。z.coerce.date() に変更することで、'2026-07-04' 形式の文字列もパース時に Date へ変換される。

// 修正後
date: z.coerce.date(),

[!WARNING] タイムゾーン(時差)の罠に注意 z.coerce.date()'2026-07-04' などの日付文字列を UTC(協定世界時)の 2026-07-04T00:00:00Z としてパースします。これをフォーマットして表示しようとすると、タイムゾーンによっては日付がずれる場合があります。UTC-X(マイナスタイムゾーン)の環境では前日にずれる可能性があります。なお JST(UTC+9)では 2026-07-04T09:00:00+09:00 として解釈されるため前日にはなりません。 画面表示時には適切なタイムゾーン補正を行うか、パース時に時差を吸収する設計が必要です。

3. 既存記事のクォート除去

問題が発生していた 7/4 以降に昇格した記事 2 本(「公開ボタンを捨てる」「ZashStudioとは何か」)の frontmatter を手動で修正した。

# 修正前
date: '2026-07-04'

# 修正後
date: 2026-07-04

やってみてわかったこと

自動化スクリプトが frontmatter を書く場合、型を意識しないと静かに壊れる。

手書きの frontmatter なら date: 2026-07-04 と自然に書ける。だがスクリプト経由だと、「日付を文字列に変換してから YAML に渡す」という不要なステップが挟まりやすい。Python の isoformat() は人間可読な文字列を返すが、それを YAML ライブラリに渡すと型情報が失われる。

再発防止として z.coerce.date() を入れたが、これはあくまで受け側の守り。スクリプト側で型を正しく扱う(datetime.date をそのまま渡す)ことが根本的な対策だ。

スキーマ側の守りも必要だが、それだけに頼ると「コードは動いているが意図と違う型で通過している」状態が続く。スクリプトが生成する frontmatter の妥当性は、astro build をローカルで毎回確認するか、CI に組み込んで検証すること。


更新履歴

  • 2026-07-18: 初稿(PR #325 を元に)