FormatArc の YAML 構文チェッカーが行番号つきでエラー表示している画面FormatArc の YAML 構文チェッカーが行番号つきでエラー表示している画面
著者: FormatArc 編集部公開日: 2026-04-13更新日: 2026-08-25

YAML 書き方ガイド|基本ルールと "Forbidden Block Composed Value" などのエラー解決

TL;DR — 1 分でわかる YAML の書き方

  • インデントはスペースのみ(タブは NG)。2 スペースが事実上の標準。
  • key: value のコロンの後にはスペースが必要。key:value は1つの文字列扱いになる。
  • リストは - (ダッシュ+スペース)、マッピングは key: value
  • 数値・真偽値・日付と誤認されそうな値はクォートする: version: "1.0"
  • エラーを素早く確認したい場合は FormatArc の YAML to JSON 変換ツール に貼り付ければ、行番号付きのエラーメッセージで問題箇所がわかります。

YAML とは、どこで使われているのか

YAML(YAML Ain't Markup Language)は、人間が読みやすいテキスト形式の構造化データフォーマットです。文字列・数値・真偽値・null・リスト・マッピングという、JSON と同じデータモデルを扱えますが、構文は括弧ではなくインデントで階層を表現します。

現代の DevOps やクラウドネイティブのツールを使っていれば、すでに YAML を目にしているはずです。

  • Kubernetes マニフェスト、Helm チャート
  • Docker Compose
  • GitHub Actions、GitLab CI、CircleCI のワークフロー
  • Ansible プレイブック
  • OpenAPI 仕様
  • 静的サイトジェネレーター(Hugo, Jekyll, Eleventy)

この記事では、実際に使う YAML の構文をすべて、具体例と初心者がハマりやすい間違いのリストとともに解説します。YAML と JSON を直接比較したい場合は YAML と JSON の違い、変換手順は YAML を JSON に変換する方法 を参照してください。

YAML を構成する 3 つの要素

YAML ファイルに現れるものは、次の 3 種類のいずれかです。

  • スカラー — 文字列・数値・真偽値・null など、単一の値
  • シーケンス — 順序付きのリスト
  • マッピング — キーと値のペア

これらは自由に入れ子にできます。マッピングがリストを含むことも、リストがマッピングを含むこともできます。これだけで、JSON と互換のある構造ならすべて表現できます。

インデント規則

YAML の階層構造はインデントで表現します。覚えておくべきルールはいくつかあります。

  • スペースのみを使う。タブ文字は多くのパーサーで構文エラー
  • インデント幅を決めたら一貫させる(通常は 2 スペース)
  • 同じ階層の要素は同じインデントにそろえる
  • 構造は閉じ括弧ではなくインデントで決まる

シンプルな有効例です。

database:
  host: localhost
  port: 5432
  credentials:
    user: admin
    password: secret

database はマッピングで、hostportcredentials を含みます。credentials はさらに入れ子のマッピングです。2 スペースのインデントで構造がひと目でわかります。

キーバリュー(マッピング)の書き方

マッピングは key: value の形式で書きます。コロンの後には半角スペースが必要です。key:value と書くと 1 つの文字列として扱われ、マッピングにはなりません。

name: Alice
age: 30
is_admin: true
bio: null

キーは通常は単純な文字列ですが、クォートすればスペースを含めることもできます。

"full name": Alice Cooper

値にはスカラー・シーケンス・マッピングなど YAML のどの型でも置けます。

リスト(シーケンス)の書き方

シーケンスは行頭に - (ハイフン+半角スペース)を置きます。

fruits:
  - apple
  - banana
  - cherry

リストには入れ子のマッピングも入れられます。

users:
  - name: Alice
    role: admin
  - name: Bob
    role: editor

ハイフンが新しいリスト項目の開始を示し、次のハイフンまでの内容がその項目に属します。

ブロック形式とフロー形式

ここまでの書き方はすべてブロック形式です。1 行に 1 項目、インデントで入れ子を表します。YAML には JSON に近いインライン(フロー)記法もあります。

fruits: [apple, banana, cherry]
users: [{name: Alice, role: admin}, {name: Bob, role: editor}]

フロー形式は短いリストでは便利ですが、データが大きくなると読みにくくなります。現実のファイルではブロック形式を使うのが無難です。フローの [ を閉じ忘れるとパーサーごとに異なるエラーが出ます。詳しくは後述のパーサー別エラー表の「フロー [ の閉じ忘れ」の行を参照してください。

文字列とクォート

YAML の文字列はほとんどの場合クォートなしで書けます。

greeting: Hello, world

クォートが必要なのは次のようなケースです。

  • 別の型として解釈されてしまう場合: version: "1.0"country: "NO"postal_code: "07030"
  • 値が YAML の構造として読まれる文字で始まる: []{},*|>%@`"'、および #&!。先頭の -:? は、直後にスペースが続くときだけ問題になります
  • 値にコロン+スペースが含まれる(マッピングと誤認されるため)
  • \n\t のようなエスケープシーケンスを使いたい

シングルクォートとダブルクォートの両方が使えます。ダブルクォートはエスケープを解釈し、シングルクォートはそのまま文字として扱います。

escaped: "line1\nline2"
literal: 'line1\nline2'

実際に問題になる文字は 2 つのグループに分かれ、そのグループがクォートの要否を決めます。次の表は、本サイトの変換ツールが使っているパーサー(yaml (eemeli) 2.8.3、YAML.parse の既定設定)の挙動です(実測 2026-08-15、再現スクリプトはリポジトリ内 scripts/benchmarks/yaml-quote-requirements/)。中央の列が「安全」なら、その文字が先頭に来ない限りクォートなしで書けます。

文字値の先頭に置いたとき値の途中に置いたとき単クォートで足りるか二重クォート
[ ] { } ,パースエラー安全足りる使ってもよい
*パースエラー(エイリアスと解釈)安全足りる使ってもよい
&エラーは出ず、アンカー扱いになって値が消える安全足りる使ってもよい
!エラーは出ず、タグ扱いになる安全足りる使ってもよい
#エラーは出ず、値全体がコメント扱いで null になる直前にスペースが無ければ安全足りる使ってもよい
| >パースエラー(ブロックスカラーと解釈)安全足りる使ってもよい
% @ `パースエラー(予約文字)安全足りる使ってもよい
- ?単独なら安全、直後にスペースが続くとパースエラー安全足りる使ってもよい
:単独なら安全、直後にスペースが続くとパースエラー直後にスペースが続くと、どこにあってもパースエラー足りる使ってもよい
"パースエラー安全足りる\" のエスケープが要る
'パースエラー安全足りない。'' と二重にするこちらを使う

ここから 2 つのことが分かります。値の途中で危険なのは : # だけなので、url: http://example.com/a,b はクォートなしのままで構いません。それ以外はすべて先頭だけの問題です。もう 1 つは、単クォートがシングルクォート文字そのもの以外のすべてを覆えることです。Windows のパスや正規表現を貼るときに単クォートのほうが安全なのはこのためで、\n\t を本物の改行やタブとして解釈させたいときだけ二重クォートを使ってください。

テンプレート構文 {{ }} を値の先頭に書くと壊れる

Helm のテンプレートや Ansible の変数展開をレンダリング前のまま YAML として読ませると、{ が特殊文字扱いになる罠を踏みます。

# レンダリング前の Helm テンプレート
image: {{ .Values.image }}

{{ はフローマッピングの開始が 2 回ネストした形として解釈されます。しかも壊れ方はパーサーによって違います。手元の実測(2026-07-12、再現スクリプトはリポジトリ内 scripts/benchmarks/yaml-syntax-errors/)では、PyYAML と ruamel.yaml は found unhashable key のエラーで止まりますが、js-yaml と eemeli/yaml はエラーを出さず{"image": {"[object Object]": null}} のような壊れたオブジェクトを黙って返しました。エラーが出ない分、後段で気づきにくいのがこの罠の厄介なところです。

対処は 2 つ。値全体をクォートして文字列にする(image: "{{ .Values.image }}")か、テンプレートをレンダリングした後の YAML だけを検証対象にすることです。なお GitHub Actions の ${{ }}$ で始まるためフローマッピングとして解釈されず、この問題は起きません。

マルチライン文字列

長いテキストには二つの書き方があります。

リテラルブロック | は改行をそのまま保持します。

description: |
  これが 1 行目です。
  これが 2 行目です。

  空行の後の 4 行目です。

フォールドスカラー > は改行を空白に畳み込むので、ソース中で折り返した長文を 1 行にまとめるのに便利です。

paragraph: >
  この長い文章はソース中で複数行に
  分けて書かれていますが、YAML は
  これを 1 行に畳み込みます。

Chomp 指示子: 末尾改行を strip / clip / keep

YAML のブロックスカラーには「末尾の改行をどう扱うか」を決める chomp 指示子があります。指示子は | または > の直後に書きます。

指示子挙動
(なし) — clip末尾改行を 1 つ残す。デフォルト。|
- — strip末尾の改行をすべて削る。|- >-
+ — keep末尾の空行をすべて残す。|+ >+
clip: |
  line one
  line two
strip: |-
  line one
  line two
keep: |+
  line one
  line two

折り畳み形式(>>->+)にも同じ 3 モードが適用されます。|- は YAML を JSON や環境変数に埋め込む際、末尾改行が邪魔になる場面で使います。|+ はシェルスクリプトを生成するときなど、末尾の空行に意味がある場面で使います。

型とパーサの型推論

YAML はクォートなしの値から型を推論します。同じリテラルでも、パーサが実装している YAML のバージョンや使っているスキーマ次第で、整数・浮動小数点数・日付・文字列のいずれにもなります。

integer: 42
hex: 0xFF              # 255 (integer, 16 進数)
octal: 0o17            # 15 (integer, 8 進数, YAML 1.2)
octal_legacy: 0644     # 420 (integer, 8 進数, YAML 1.1) — ファイルモードの罠
float: 3.14
negative: -7
exponential: 1e3       # 1000.0 (float, 指数表記)
infinity: .inf         # +Infinity (float)
negative_infinity: -.inf
not_a_number: .nan     # NaN (float)
boolean_true: true
boolean_false: false
null_value: null
tilde_null: ~
date: 2026-04-13
timestamp: 2026-04-13T09:30:00Z

これらはいずれもクォートすれば文字列として固定できます。

version_string: "1.0"    # 数値の 1.0 ではない
zip_code: "07030"        # 数値の 7030 ではない
file_mode: "0644"        # 文字列。8 進整数ではない

次の表は、クォートなしのリテラルが、現代的な YAML 1.2 Core スキーマのローダー(PyYAML、js-yaml、SnakeYAML のデフォルト)と、YAML 1.1 のローダー(古い PyYAML、Symfony YAML)でそれぞれ何になるかをまとめたものです。意外な挙動のほとんどは、この 2 列の差に潜んでいます。

リテラルYAML 1.2 CoreYAML 1.1注意点
42integer (42)integer (42)
0xFFinteger (255)integer (255)16 進パースは意図的な仕様
0o17integer (15)(認識されない)YAML 1.2 のみ
0644integer (644)integer (420, 8 進)ファイルモードがバージョンで変わる
1e3float (1000.0)float (1000.0)一部ツールは表示で .0 を落とす
.inf / -.inffloat (±Infinity)float (±Infinity)JSON にシリアライズ不可
.nanfloat (NaN)float (NaN)JSON にシリアライズ不可
2026-04-13stringdate (日付オブジェクト)JSON ↔ YAML の往復で型が変わる
2026-04-13T09:30Zstringtimestamp同じ問題
true / falsebooleanboolean
yes / no / on / offstringboolean「Norway problem」
NOstringboolean (false)次節で扱う
~ / null / Null / NULLnullnullどの大文字小文字でも null
1.0float (1.0)float (1.0)一部ツールは 1 として再シリアライズ

パーサが少しでも本番に近いなら、いちばん右の列にあるものはすべて潜在的なバグとして扱ってください。手元のローダーがどのバージョンを使っているかを知る最速の方法は、代表的なファイルを FormatArc の YAML to JSON 変換ツール に貼り付けて JSON 出力を確認することです。"NO"false か、"2026-04-13" か ISO の日付文字列か、といった具合に判別できます。

この 2 列の差が生まれるのは、YAML 1.1 と YAML 1.2 で型推論の定義が異なるためです。YAML 1.1 は、タイムスタンプ・60 進数(base-60)・Norway problem を引き起こす幅広い真偽値の語彙を含む、広範な暗黙の型タグを抱えていました。YAML 1.2 はそれを、より狭い Core スキーマ別タブで開きます に置き換えました。Core スキーマは真偽値を truefalse に限定し(仕様の Core 正規表現は先頭大文字や全大文字の True/TRUE/False/FALSE も受理しますが、yes/no/on/off はもう受理しません)、暗黙のタイムスタンプおよび 60 進数タグを廃止し、それ以外は JSON の値型を踏襲します。リテラルが整数・浮動小数点数・真偽値・null のどれになるかを決める正規表現の完全なセットは YAML 1.2.2 仕様別タブで開きます に公開されています。2 つのツールがクォートなしの値の意味で食い違うとき、その違いはほぼ必ず、一方が 1.1 の型ルールを、もう一方が 1.2 の Core スキーマを実装していることに行き着きます。

Norway problem — NOfalse に化ける罠

YAML でもっとも有名な落とし穴が「Norway problem」です。YAML 1.1 のパーサ(PyYAML、Symfony YAML、古い SnakeYAML など、いまだに広く使われています)はクォートなしの NO を真偽値 false として解釈します。次のような国コードのリストは:

countries:
  - DE
  - FR
  - NO
  - SE

パースされた瞬間に ["DE", "FR", false, "SE"] になってしまいます。YESONOFFYN、さらに大文字小文字違いまでパーサ次第で同じ罠を踏みます。

回避策は誤解されうる値をクォートすることです:

countries:
  - "DE"
  - "FR"
  - "NO"
  - "SE"

YAML 1.2 では true / false のみに絞られましたが、本番ツールの多くはいまだに 1.1 系のローダーを同梱しています。国コード・言語コード・バージョン文字列・短い識別子などはすべてクォートしておくのが安全です。パーサを問わない設定を維持したい場合は FormatArc の YAML to JSON 変換ツール に貼り付ければ、出力された JSON で "NO" が文字列のまま残っているか即座に確認できます。

具体的なルールは公式仕様で定義されています。今日の厳密な真偽値集合を定めるのが YAML 1.2.2 仕様別タブで開きます、レガシーツールが現在もそのまま実装しているのが YAML 1.1 仕様別タブで開きます です。手元のローダーがどちらに準拠しているかを把握しておくと、NO が文字列として残るか false になるかを判断できます。

コメント

コメントは # から行末までです。単独の行にも、値の後ろにも書けます。

# 上流リクエストの最大リトライ回数
retries: 3  # これ以上は上流のタイムアウトを超えてしまう

コメントは設定ファイルにおける YAML の最大の強みのひとつです。「何をしているか」ではなく「なぜこの値なのか」を説明するのに使ってください。JSON に変換するとすべて消えるので、YAML を一次ソースとして保管するのが安全です。JSON でどうしてもコメントを書きたい場合は JSON にコメントを書く方法 で JSONC / JSON5 の回避策を解説しています。

アンカーとエイリアスで再利用する

YAML は & でアンカーを打ち、* でエイリアスを参照できます。<<: のマージキーでマッピングをデフォルト値として取り込めます。

defaults: &defaults
  adapter: postgres
  host: db.internal
  pool: 5

development:
  <<: *defaults
  database: myapp_dev

production:
  <<: *defaults
  database: myapp_prod
  pool: 20

productiondefaults を引き継ぎつつ pool を上書きしています。環境ごとの設定をコピペせずに共通化できる、きれいな書き方です。

マージキー(<<:)で設定を共有する

<<: のマージキーはアンカーともっとも相性のよい機能です。あるマッピングのキーを別のマッピングに取り込めるので、「同じだけどここだけ上書き」を繰り返さずに表現できます。Docker Compose、GitLab CI、Rails の database.yml など、設定ファイルの実例で頻出します。

base: &base
  image: node:20
  restart: unless-stopped
  environment:
    NODE_ENV: production

services:
  api:
    <<: *base
    command: npm run start:api
  worker:
    <<: *base
    command: npm run start:worker
    environment:
      NODE_ENV: production
      WORKER_QUEUE: high

注意点が 2 つあります。

  • マージキーは 1 階層だけしか合成しません。ネストしたマッピング(上の例の environment など)は深くマージされず、丸ごと上書きされます。
  • マージキーは YAML 1.1 の機能です。厳密な YAML 1.2 パーサは無視することがありますが、Docker Compose や GitLab はいまだに 1.1 セマンティクスをサポートしているため使えます。

スキーマとタグ: YAML はどう型を決めるのか

YAML 1.2 は、クォートなしのリテラルの解釈方法を制御する 3 つのスキーマを定義しています。

  • FailSafe — 文字列・マッピング・シーケンスのみ。もっとも安全なスキーマで、それ以外はすべて文字列になります。デフォルトになることはほとんどありません。
  • JSON — JSON 互換の型(文字列・整数・浮動小数点数・真偽値・null・マッピング・シーケンス)。JSON.parse が生成するものと一致します。
  • Core — 一般的なデフォルト。上の表の型推論ルール(hex・octal・.inf.nan~)を追加します。

ほとんどのパーサは Core を同梱します(PyYAML の safe_load、js-yaml のデフォルト、SnakeYAML の SafeConstructor)。Symfony YAML はいまだに YAML 1.1 セマンティクスをデフォルトにしています。手元のローダーがどのスキーマを使うかを知れば、型の表のどの行が適用されるかがわかります。

スキーマが取り違える場合 — 文字列にしたかったのに version: 1.0 が浮動小数点数としてパースされるなど — は、明示的なタグで上書きします。

version: !!str 1.0       # 文字列 "1.0" に強制する
count: !!int "42"        # クォートされていても整数 42 に強制する
empty: !!null ""         # 空文字列ではなく明示的な null

!! プレフィックスは「デフォルトのタグライブラリのタグを使う」という意味です。カスタムタグは単一の ! を使い(たとえば CloudFormation テンプレートの !Ref)、パーサ側がそれを理解している必要があります。アプリケーションレベルの YAML ファイルのほとんどは、型の罠を解除するために !!str だけあれば十分です。

マルチドキュメント

1 つの YAML ファイルに複数のドキュメントを入れることができます。区切りは --- の行です。

---
kind: Service
name: web
---
kind: Deployment
name: web
replicas: 3

Kubernetes で複数マニフェストを 1 ファイルにまとめるときに使う形式です。JSON にはこれに相当する仕組みがないため、変換時はどちらか一方を選ぶか、外側を配列でラップする必要があります。

アンカー・マージキー・マルチドキュメントはどこで使えるか(対応表)

ここまで紹介したアンカー・マージキー・マルチドキュメントは「YAML の文法としては正しいのに、使う場所によって通ったり通らなかったりする」機能です。パーサー 4 種と Docker Compose は手元で実測(2026-07-12、再現スクリプトはリポジトリ内 scripts/benchmarks/yaml-tool-acceptance/)、ホスト型サービスは公式情報を確認しました。

環境アンカー & *マージキー <<:マルチドキュメント ---
js-yaml対応(実測)対応(実測)load はエラー。loadAll で対応(実測)
PyYAML対応(実測)対応(実測)safe_load はエラー。safe_load_all で対応(実測)
yaml (eemeli)(FormatArc の変換ツールが使うパーサー)対応(実測)既定では展開されず << が文字通りのキーとして残る(実測)parse はエラー。parseAllDocuments で対応(実測)
Docker Compose v5.3.0対応(実測)対応(実測)複数ドキュメントを 1 つの構成にマージして受理(実測)
GitHub Actions2025-09-18 から対応別タブで開きます未対応 — 使うと構文エラー別タブで開きます公式ドキュメントに記載なし
GitLab CI対応別タブで開きます対応別タブで開きます公式ドキュメントに記載なし
Kubernetes (kubectl)公式ドキュメントに明示なし公式ドキュメントに明示なし対応別タブで開きます

読み方のポイントは 3 つあります。

  • GitHub Actions はアンカー対応とマージキー未対応が分かれている。2025-09 のアンカー対応後も <<: は構文エラーになるため、GitLab CI から workflow を移植するときにそのまま持ち込めません。
  • eemeli/yaml は既定で YAML 1.2 準拠のため、YAML 1.1 由来のマージキーを展開しません。{"<<": {...}} というキーがそのまま残ってしまい、エラーにならない分だけ気づきにくい挙動です。
  • マルチドキュメントは「どの API で読むか」の問題です。4 パーサーとも単発読み込み API ではエラーになり、複数ドキュメント用 API に切り替えると通ります。

実際に YAML を書く 3 つの場面

数行の設定ファイルでも本番マニフェストでも、適用される文法は同じです。2026 年の開発で YAML に出会う典型的な 3 つの場面を紹介します。

Kubernetes Deployment マニフェスト

最小構成の Deployment でも、マッピング・シーケンス・マルチライン文字列・Norway problem 系のブール値がすべて登場します。spec.template.spec.containers あたりのインデントずれが失敗の典型です。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  labels:
    app: web
    tier: frontend
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: nginx:1.27-alpine
          ports:
            - containerPort: 80
          env:
            - name: FEATURE_FLAG_NEW_HEADER
              value: "true"      # 意図的にクォート — 裸の true はブール扱い
          resources:
            limits:
              cpu: "500m"
              memory: 256Mi

value: "true" をクォートしているのが要点です。クォートを外すと Kubernetes はブール値として受理し、コンテナには言語次第で True(Python 風)が渡るか起動失敗します。具体的な失敗パターンは次節で扱います。

GitHub Actions ワークフロー

GitHub Actions のワークフローはマッピングが深くネストし、run ブロックでマルチライン文字列が頻出します。|(リテラル)と >(フォールド)の使い分けが効いてくる場面です。

name: CI
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: "20"      # 末尾 0 を保つためクォート
      - name: Install
        run: npm ci
      - name: Test
        run: |
          npm run lint
          npm run build
          npm test -- --run

ここでもっとも多い破壊は node-version: "20" のクォートを外してしまうことです。YAML が整数 20 に強制変換するため、setup-node のバージョンによっては受理されません。「数字に見えるが文字列でなければならない」値はすべてクォートしてください。

Docker Compose のサービス定義

Compose ファイルはマッピング・シーケンス・環境変数辞書・バインドマウント文字列が混在する短い YAML です。インデント問題の練習にちょうどよい長さです。

services:
  web:
    image: nginx:1.27-alpine
    ports:
      - "8080:80"               # 60 進数として解釈されないようクォート
    environment:
      NGINX_HOST: example.com
      NGINX_PORT: "80"          # クォート必須: 環境変数値は文字列
    volumes:
      - ./html:/usr/share/nginx/html:ro
    depends_on:
      - api
  api:
    build: ./api
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/health"]
      interval: 30s
      timeout: 5s
      retries: 3

落とし穴は 2 つ。"8080:80" のクォートを外すと YAML 1.1 系パーサが 60 進数として読みうる点と、environment: 配下は最終的に文字列として渡されるため値はクォートしておく方が安全である点です。次節で具体的な失敗例を見ていきます。

よくある間違いと見つけ方 — 同じ間違いにパーサーは何と言うか(実測)

多くの開発者が一度はハマる YAML の落とし穴です。

  • タブ文字でインデントしている — 見えないタブが混入すると分かりにくいエラーになる
  • コロンの後にスペースがない — key:value は 1 つの文字列として扱われる
  • インデントがそろっていない — 同じ階層の要素は同じ幅でそろえる必要がある
  • クォートなしの NOOFFYESON が真偽値になる(ノルウェー問題)
  • クォートなしの値にコロンが含まれる — time: 10:30 が 60 進数として解釈されることがある
  • ブロック形式とフロー形式の混在でパーサーが混乱する
  • 同じマッピング内で重複キーを使う — 実装依存の挙動になる

エラーメッセージで検索したとき困るのは、同じ間違いでもパーサーごとにまったく別の文言を返すことです。代表的な 6 つの間違いを js-yaml と、FormatArc の変換ツールが使う yaml (eemeli) と、PyYAML に実際に食わせて、出てきたエラー文字列を記録しました(実測 2026-07-12、ruamel.yaml を含む全 4 パーサーの生ログと再現スクリプトはリポジトリ内 scripts/benchmarks/yaml-syntax-errors/)。再現スクリプトには 7 件目として {{ }} のテンプレート罠も入っていますが、これは上の専用セクションで扱っているため、この表には重ねていません。

間違いjs-yaml のエラーyaml (eemeli) のエラーPyYAML のエラー
タブでインデントtab characters must not be used in indentation (2 行目)Tabs are not allowed as indentation (2 行目)found character '\t' that cannot start any token (2 行目)
インデント不揃い(2 と 3 スペース混在)bad indentation of a mapping entry (3 行目)Nested mappings are not allowed in compact mappings (2 行目)mapping values are not allowed here (3 行目)
値の中のクォートなし : url: http://x.com: 8080bad indentation of a mapping entry (1 行目 24 列)Nested mappings are not allowed in compact mappings (1 行目 6 列)mapping values are not allowed here (1 行目 24 列)
ダブルクォート閉じ忘れunexpected end of the stream within a double quoted scalar (末尾行)Missing closing "quote (2 行目 8 列)while scanning a quoted scalar ... found unexpected end of stream(開始クォート位置を指す)
未定義アンカーへの *aliasunidentified alias "missing"Unresolved alias (the anchor must be set before the alias): missing(行番号は返らない)found undefined alias 'missing'
フロー [ の閉じ忘れmissed comma between flow collection entries (次行)Flow sequence in block collection must be sufficiently indented and end with a ] (2 行目)while parsing a flow sequence ... expected ',' or ']'

読み方のコツが 3 つあります。まず mapping values are not allowed here(PyYAML)と bad indentation of a mapping entry(js-yaml)は別物に見えて、どちらも「意図しない場所に : がある」ことを指す兄弟エラーです。eemeli の Nested mappings are not allowed in compact mappings も、同じ診断を 3 つ目の言い回しにしたものです。次に、エラーの指す行番号はパーサーによってずれます。クォート閉じ忘れでは js-yaml がストリーム末尾を、PyYAML が開きクォートの位置を指すため、「エラー行の 1 行前後と、クォートの開始位置」の両方を疑うのが早道です。3 つ目に、同じ文書でも eemeli は js-yaml より 1 行手前を指すことがあります。壊れた位置ではなく、コンパクトマッピングが始まった位置を報告するためです。

こうした間違いを一番早く見つける方法は、パーサーに読ませることです。インストール不要で試すなら、FormatArc の YAML to JSON 変換ツール に貼り付けるだけでチェックできます。正しい YAML なら JSON が即座に表示されます。間違っていれば構文エラーであることと、飛ぶべき行番号が表示されます。パーサーの生のメッセージはあえて出していないので、自分の環境が返す文言そのもので検索したいときは上の表を使ってください。

"It is forbidden to specify block composed value at the same line as key" を解決する

これは JetBrains/IntelliJ 系 IDE (IntelliJ IDEA、PyCharm、GoLand、Rider、DataGrip) の YAML inspection が出すメッセージです。文言そのものは YAMLBundle.properties別タブで開きますannotator.same.line.composed.value.message として定義されています。

意味は 1 つだけで、ブロックコレクションがキーと同じ行から始まっていることを指します。annotator の実装別タブで開きますを読むと、検査しているのは 2 つの形だけです。ブロックシーケンスの最初の要素がキーと同じ行にある場合と、ブロックマッピングの最初のキーバリューがキーと同じ行にある場合です。それ以外では発火しません。

形 1: ブロックシーケンスがキーの行から始まっている。

# このパターンで inspection が出る
key: - item1
     - item2

対処: 最初の要素を次の行に下ろします。

key:
  - item1
  - item2

形 2: ブロックマッピングがキーの行から始まっている。

# このパターンで inspection が出る
key: sub: value
     sub2: value2

対処: 同じくコロンの後で改行します。

key:
  sub: value
  sub2: value2

どちらも IDE の好みの問題ではなく YAML として不正です。パーサも IntelliJ に近い文言で拒否します。yaml パッケージは形 1 に Unexpected block-seq-ind on same line with key、形 2 に Nested mappings are not allowed in compact mappings を返します。

重複キーの inspection とは別物です。 マッピングのキーが重複している場合は Key 'x' is duplicated という別のメッセージが出ます (同じバンドルの YAMLDuplicatedKeysInspection.duplicated.key)。キーが重複していると言われたときの対処はキーの改名か親ノードの付け替えで、ブロックコレクションの位置とは関係ありません。

Helm や Jinja のテンプレートで出た場合。 annotator はテンプレート言語の注入要素を含む場合に検査を打ち切るため、正しく書かれたテンプレートは本来フラグされません。それでも出るなら既知の false positive で (IJPL-64437別タブで開きます など)、ファイル側を直す必要はありません。

修正後は YAML to JSON に貼り付けて、ブロックコレクションが自分の行から始まっていることを確認できます。変換はすべてブラウザ内で完結し、貼り付けた YAML はアップロードされません。

FormatArc でブラウザ内 YAML バリデーション

FormatArc のブラウザ完結ツールは簡易 YAML リンターとしても使えます。

YAML to JSON の変換結果、行番号付きで構文チェックが通った画面YAML to JSON の変換結果、行番号付きで構文チェックが通った画面

  • YAML to JSON — YAML を貼り付けて JSON を得る。エラー時は行番号付きで表示
  • JSON to YAML — JSON から出発して YAML の形を学びたいときに
  • JSON Formatter — 変換結果の JSON を整形・エラー表示する

すべてブラウザで完結します。内部の設定ファイルやシークレットをデバッグ中に貼り付けても、データは手元から出ません。

よくある質問

YAML のインデントにタブを使えますか?

使えません。YAML 仕様はスペースのみを許容しており、タブ文字は多くのパーサーで構文エラーになります。.yml.yaml の編集時は Tab キーで 2 スペースが入るようにエディタを設定してください。

.yml.yaml の違いは?

違いはありません。どちらの拡張子も YAML パーサーはまったく同じように扱います。公式仕様では .yaml を推奨していますが、.yml も広く使われていて問題ありません。

文字列は必ずクォートすべきですか?

いいえ、基本的にはクォートなしで書けます。クォートが必要なのは、別の型として解釈されてしまう値や、特殊文字 -:[{|> で始まる値です。

version: 1.0 と書いたのに 1 になってしまうのはなぜですか?

YAML は 1.0 を浮動小数点数としてパースし、一部のツールはそれを 1 としてシリアライズし直します。文字列として保持したい場合は version: "1.0" のようにクォートしてください。

インデントのスペース数はいくつが正解ですか?

2 スペースが慣習です。Kubernetes、Docker Compose、GitHub Actions など、ほとんどの例が 2 スペースを使っています。4 スペースでも動きますが、1 つのファイル内では必ず統一してください。

インストールせずに YAML を検証する方法は?

FormatArc の YAML to JSON 変換ツール に貼り付けるだけで検証できます。有効な YAML なら即座に JSON が出力され、無効なら行番号付きのエラーメッセージが表示されます。

1 つのファイルに複数の YAML ドキュメントを入れられますか?

入れられます。区切りは --- だけの行です。Kubernetes でマニフェストをまとめるときの標準的な形式です。1 ファイルにいくつでもドキュメントを並べられます。

関連記事

まとめ

  • YAML は括弧ではなくインデントで構造を表現します
  • インデントはスペースのみで、一貫させることが重要です
  • 文字列は誤解釈されるときだけクォートします
  • コメント・マルチライン・アンカーで設定ファイルを読みやすくできます
  • 構文の検証は FormatArc の YAML to JSON ツール に貼り付けるのが最速です