Skip to content

ガイド

YAML 1.1 と 1.2

最も高くついたYAMLのバグの中心には、国コードがある。

著者 yamltojsonfree · 公開日 · 更新日

Norway問題とは

YAML 1.1では、引用符のない y、yes、on、n、no、off は真偽値です — 大文字でも小文字でも先頭だけ大文字でも。そのためノルウェー(NO)を含む国コードのリストは、静かに false になります。エラーは出ません。ドキュメントは解析され、デプロイは成功し、下流のどこかで「真偽値は辞書のキーになれず文字列比較にも一致しない」という理由で、リストから国が1つ消えます。

2009年に公開されたYAML 1.2はこれを廃止しました。真偽値は true と false だけで、先の6語は通常の文字列です。YAML 1.1の他の暗黙変換も廃止されました — 022 はもう18を表す8進数ではなく、12:30 はもう750を表す60進数ではありません。

問題は、15年以上経った今も両バージョンが広く使われていることです。同じファイルが、開くツールによって2つの異なる意味を持ちうる — だからこそこのサイトのYAML→JSON変換ツールはデフォルトでYAML 1.2を使い、1.1では異なって読まれるドキュメント内の値をすべて警告します。

意味が変わる値の一覧

同じソースを、仕様の各バージョンで読んだ結果。

YAMLソースYAML 1.2での解釈YAML 1.1での解釈安全な書き方
country: NO"NO"falsecountry: "NO"
enabled: yes"yes"trueenabled: true
debug: off"off"falsedebug: false
mode: 0222218mode: "022"
start: 12:30"12:30"750start: "12:30"
version: 1.101.11.1version: "1.10"

最後の行に注目してください。1.10 は数値として解析されるため、どちらのバージョンでも末尾のゼロを失います。バージョン文字列は常に引用符で囲むべきです。

どのパーサーがどのバージョンを読むか

YAMLのバージョンを直接選ぶことはめったにありません — 使っているツールが依存するライブラリから継承します。エコシステムはおおむね次のように分かれています:

パーサーバージョン備考
PyYAML (Python)YAML 1.1Ansibleを含む多くのPythonツールのデフォルト。
ruamel.yaml (Python)YAML 1.2メンテナンスされているPyYAMLの後継。オプションで1.1も可。
js-yaml v5 (JavaScript)YAML 1.2このサイトが使うエンジン。以前のバージョンは1.1を読んでいた。
go-yaml / sigs.k8s.io (Go)ほぼ1.2Kubernetesが使用。互換性のため一部1.1の挙動を残す。
SnakeYAML (Java)YAML 1.1Spring Bootの設定読み込みのデフォルト。
libyaml (C bindings)YAML 1.1PyYAMLを含む多くの言語バインディングの基盤。

実務上の帰結:この表の片側で書かれ、反対側で読まれるファイルは、値が静かに変わりうるということです。YAMLをPythonで生成しKubernetesで消費する — とてもよくあるパイプラインです — なら、バージョンの境界を越えています。コードレベルの詳細はガイドコードでYAMLをJSONに変換するにあります。

両バージョンで安全なYAMLの書き方

3つの習慣でこの種のバグは丸ごと消えます。別のものと誤解されうる文字列はすべて引用符で囲む — 国コード、バージョン番号、先頭にゼロが付く値、コロンを含むものすべて。真偽値は true と false だけで書き、yes や on やその仲間は使わない。そしてファイルがツール間を渡る前に、バージョン依存の値を報告する変換ツールかバリデーターに通す — YAMLを明示的なJSONとして見るのが、意図しない型を見つける最速の方法です。

参考資料