YAML とは?書き方と、よくあるエラー(mapping values are not allowed など)の読み方

PR
YAML とは?書き方と、よくあるエラー(mapping values are not allowed など)の読み方
この記事は約38分で読めます。

YAML は、設定やデータを、行の頭の空白(字下げ)で入れ子にして書く、人が読み書きしやすいデータの書き方です。GitHub Actions の workflow や Docker Compose の compose.yaml など、設定ファイルでよく見かけます。

この記事は、YAML のファイルを初めて見た人や、mapping values are not allowed のようなエラーが出て困っている人向けです。基本の書き方、JSON・TOML との違い、引用符、複数行の文字列、1.10 や yes が別の値として読まれる注意、エラーの文から原因を引く読み方を、2026年10月14日時点の YAML の仕様と、PyYAML 6.0.3・js-yaml 5.4.3・Docker Compose を動かした結果をもとにまとめました。

この記事でわかること
  • YAML は何の略で、何に使われるか(GitHub Actions・Docker Compose など)と、YAML 1.1・1.2 という版があること
  • 基本の書き方(キーと値・リスト・字下げ・コメント)と、字下げにタブを使えないこと
  • 引用符で囲まない値が 1.10 → 1.1 や yes → true のように読まれることがある理由と、パーサー(YAML を読む道具)による違い
  • エラーの文から原因を引く読み方。同じまちがいでも、パーサーと版で文が違うこと
  • エラーにならずに意味が変わるまちがいは、読み込んだ結果を見て確かめること

この記事で確かめた版(2026年10月14日時点)

  • 仕様: YAML 1.2.2(2021年10月1日の改訂)が最新です。YAML 1.1 の仕様は 2005年1月18日付の最終案(Final Draft)です
  • 手元で動かしたもの: macOS 14.4.1(Apple Silicon)、PyYAML 6.0.3(libyaml 0.2.5 つき・Python 3.12.3)、js-yaml 5.4.3(Node.js v21.7.1)、Docker Compose v5.6.0(GitHub の配布物の単体の実行ファイル)と v2.38.2-desktop.1(この Mac の Docker Desktop に入っていたもの)
  • PyYAML 6.0.3 は PyPI の最新版(2025年9月25日(UTC)に公開)、js-yaml 5.4.3 は npm の最新版、Compose v5.6.0 は GitHub の最新版(2026年10月2日(UTC)に公開)です。Docker Desktop に入っていた v2.38.2 は最新ではありませんでした
  • エラーの文は、パーサーと版で違います。 この記事で文を引くときは、必ず「どのパーサーの、どの版が出した文か」を一緒に書きます
  • Windows では流していません。GitHub の上(GitHub のサーバー)でも流していません。ほかのパーサー(Ruby の Psych・Go の yaml ライブラリを直接・js-yaml 4 系・ruamel.yaml など)と、Python の別の版も流していません
  1. YAML とは?何の略で、何に使われる?
    1. 何の略か
    2. 身近な例:GitHub Actions と Docker Compose
    3. YAML 1.1 と 1.2:版がある
  2. YAML の基本の書き方(キーと値・リスト・入れ子・コメント)
    1. 記号の決まり
    2. 字下げで入れ子を表す
    3. コメント
    4. 1行で書く「流れの書き方」
  3. YAML と JSON・TOML の違いは?
    1. JSON との違い
    2. TOML との違い:なぜ pyproject.toml は YAML ではないのか
  4. 文字列と引用符(' と ")の使い分けと、複数行の書き方
    1. 引用符で囲まない値に入れられないもの
    2. 一重引用符と二重引用符
    3. 値の頭で特別な意味を持つ記号
    4. 値の一部だけを引用符で囲んでも直らない
    5. 複数行の文字列はどう書く?(リテラルと折りたたみ)
  5. 数や true/false に化ける値は?(1.10・yes/no・on/off)
    1. 版番号の 1.10 が 1.1 になる
    2. yes・no・on・off は真偽値になるのか
    3. 0 から始まる数・60進数・日付
    4. Docker Compose の場合:文書と手元の結果が違う
    5. GitHub Actions の on: と PyYAML
  6. よくあるエラーの読み方(エラーの文から引く)
    1. まず早見表
    2. エラーの場所の読み方
    3. mapping values are not allowed(here / in this context)
    4. found character that cannot start any token
    5. did not find expected key
    6. did not find expected '-' indicator
    7. found unexpected end of stream
    8. found undefined alias(unknown anchor)
    9. duplicated mapping key(同じキーを2回書いた)
    10. TypeError: load() missing 1 required positional argument: 'Loader'
    11. エラーにならずに意味が変わるまちがい
  7. GitHub Actions と compose.yaml を読んでみる
    1. GitHub Actions の workflow
    2. compose.yaml とアンカー
  8. よくある質問
    1. YAML の読み方は?
    2. .yml と .yaml はどちらを使えばいいですか?
    3. コメントアウトのしかたは?複数行は?
    4. インデントのエラーの場所がわからないときは?
    5. 書いた YAML のエラーをチェックするには?
  9. まとめ
  10. 参考資料

YAML とは?何の略で、何に使われる?

最初に言葉を説明します。パーサーは、YAML の文字を読み取って、プログラムが扱えるデータ(文字列・数・リストなど)に変える道具です。PyYAML は Python 用、js-yaml は JavaScript 用のパーサーです。

何の略か

YAML は「YAML Ain't Markup Language」の略です(自分の名前を中に含む、再帰的な略語です)。YAML 1.2.2 の仕様は、人が読み書きしやすく、プログラミング言語とよく合うように作られた、データを文字で書き表すための言語(データのシリアライズ言語)と説明しています。

設定ファイルによく使われますが、仕様は「もともと、そしてこれからも、完全なデータのシリアライズ言語」と書いています。

身近な例:GitHub Actions と Docker Compose

  • GitHub Actions: workflow のファイルは YAML で書きます。拡張子は .yml か .yaml で、置き場はリポジトリの .github/workflows です(GitHub の文書より)。workflow の書き方は、GitHub Actions とは?使い方と、安全に使うための設定(権限・SHA 固定・secrets)で説明しています
  • Docker Compose: Compose ファイルとして YAML の設定ファイルを使います。既定の名前は compose.yaml(推奨)か compose.yml で、古い版との互換のために docker-compose.yaml・docker-compose.yml も読みます。両方あれば compose.yaml を使います(Docker の文書より)。Compose とは何かは、【完全入門】docker?docker compose?違いと使い分けで説明しています。その記事は docker-compose.yml の名前で書いていますが、今の既定の名前は compose.yaml です

YAML 1.1 と 1.2:版がある

YAML には版があります。1.0 は2004年のはじめ、1.1 は2005年、1.2 は2009年、1.2.2 は2021年10月に出ました。1.2.2 は、1.2 からの規範(守るべき決まり)の変更が無く、間違いを直し、わかりやすくした改訂です。

パーサーがどの版に対応しているかは、道具で違います。

  • PyYAML は、PyPI の説明に「YAML 1.1 のパーサー」とあります
  • js-yaml は、README に「JavaScript の YAML 1.2 のパーサー」とあり、「YAML 1.2 と 1.1 の仕様に対応」とも書かれています

この違いは、あとの「数や true/false に化ける値」で効いてきます。

YAML の基本の書き方(キーと値・リスト・入れ子・コメント)

まず、よく見る形を1つ見ます。次の YAML は、手元で PyYAML 6.0.3 と js-yaml 5.4.3 に読ませたものです(名前やメールアドレスはダミーです。手元で読ませた YAML の一部を省いて載せています)。

# コメントは # から行の終わりまで
name: my-app        # 行の途中のコメント
port: 8080
debug: false
tags:
  - web
  - api
owner:
  name: alice
  email: alice@example.com
flow_list: [a, b, c]
flow_map: {x: 1, y: 2}

PyYAML 6.0.3 で読むと、次のデータになりました(Python の書き方での表示です。js-yaml 5.4.3 でも同じデータでした。一部を省いて載せています)。

{'name': 'my-app', 'port': 8080, 'debug': False, 'tags': ['web', 'api'], 'owner': {'name': 'alice', 'email': 'alice@example.com'}, 'flow_list': ['a', 'b', 'c'], 'flow_map': {'x': 1, 'y': 2}}

記号の決まり

  • キーと値は、: と空白で区切ります(name: my-app)
  • リストの各項目は、- と空白で始めます(- web)
  • コメントは # で始めます

どの記号も、そのあとの空白が決まりの一部です。: や - のあとに空白が無いと、キーと値・リストとして読まれません(あとの「エラーにならずに意味が変わるまちがい」で説明します)。

字下げで入れ子を表す

YAML のブロックの書き方では、入れ子の構造は字下げで決まります。字下げは、行の頭の空白(スペース)の数です。上の例の owner: の下の name: と email: は、空白2つで下げてあるので、owner の中身として読まれます。

  • 字下げにタブは使えません。 環境によってタブの扱いが違うためで、仕様は、多くのエディターは Tab キーで空白が入るように設定できる、とも書いています。PyYAML の文書も「YAML でのタブの扱いは、使わないのが一番」という趣旨のことを書いています
  • 空白をいくつ入れるかについて、仕様は「字下げの量は見た目の話で、中身の情報に使ってはいけない」と書いています。「2つでなければならない」という決まりは、仕様には書かれていません。この記事の例は2つで下げています
  • ただし、同じ階層のキーの字下げは揃えます。 揃っていないとエラーになることを、あとの「よくあるエラーの読み方」で確かめます

コメント

コメントは # から行の終わりまでです。仕様は、# はほかの記号と空白で離すと書いています。手元の結果では、hash_in_value: a#b の値は 'a#b'(コメントにならない)、hash_after_space: a #b の値は 'a'( #b がコメント)でした。PyYAML 6.0.3・js-yaml 5.4.3 とも同じです。

1行で書く「流れの書き方」

リストを [ ]、キーと値の組を { } で、1行に書く書き方もあります(上の flow_list と flow_map)。字下げで書く形をブロック、この形を流れ(フロー)と呼びます。

YAML と JSON・TOML の違いは?

JSON との違い

YAML 1.2 は、JSON を厳密に含むこと(JSON の書き方をそのまま YAML として読めること)を主な狙いにして作られました。同時に、問題の多かった「書き方から型を推し量る決まり」の多くを外しています。1.1 のころは、JSON は「たまたま、ほぼ YAML の部分集合」だったと、仕様の歴史の節に書かれています。

手元でも、JSON の文を YAML として読ませて、同じデータになることを確かめました。

{"name": "my-app", "port": 8080, "tags": ["web", "api"], "debug": false, "owner": null}

PyYAML 6.0.3 は {'name': 'my-app', 'port': 8080, 'tags': ['web', 'api'], 'debug': False, 'owner': None}、js-yaml 5.4.3 は {"name":"my-app","port":8080,"tags":["web","api"],"debug":false,"owner":null} になりました。

YAML 側にある書き方は、次のとおりです。

  • コメントが書けます(#)
  • 字下げで入れ子を書くブロックの書き方があります
  • 複数行の文字列の書き方があります(あとの節)
  • アンカー(&)とエイリアス(*)があります(あとの節)

なお、YAML の流れの書き方([ ]・{ })は JSON に見えることがあります。YAML のメディアタイプを決めた RFC 9512 は、このとき JSON と同じ相互運用の注意が当てはまる、と書いています。

TOML との違い:なぜ pyproject.toml は YAML ではないのか

TOML も設定を書くための書式です。Python のプロジェクトの設定ファイル pyproject.toml は、YAML ではなく TOML で書きます。その理由を、PEP 518(Python の仕様の提案)が書いています。YAML については、次の3つです。

  1. 仕様が大きい(印刷すると、レターサイズの紙で86ページ)ので、あるパーサーでは動き、別のパーサーでは動かない機能を使ってしまうおそれがある
  2. YAML は既定では安全ではない(PyYAML には safe_load があるが、道具がうっかり load を使うと任意のコードが動く)
  3. よく使われる PyYAML は大きく、pip が中に抱えるのが重い

2つ目は、PEP 518 の書き手の見方です。YAML の仕様が「安全ではない」と書いているわけではありません。PyYAML の load と safe_load の違いは、あとの「よくあるエラーの読み方」で説明します。

pyproject.toml の書き方は、pyproject.toml とは?requirements.txt との違い【pip 26.2・uv 0.13】で説明しています。

文字列と引用符(' と ")の使い分けと、複数行の書き方

YAML では、文字列を引用符で囲まなくても書けます。引用符で囲まない書き方をプレーンといいます。仕様は、プレーンを、記号の逃がし(エスケープ)が無く、いちばん読みやすい一方で、いちばん制限が多く、前後の文脈で意味が変わる書き方と説明しています。

引用符で囲まない値に入れられないもの

プレーンの値には、: (コロンと空白)と #(空白とシャープ)を入れられません。キーと値の組・コメントと区別できなくなるためです。値に入れたいときは、引用符で囲みます。

一重引用符と二重引用符

書き方中で使える逃がし手元の例(PyYAML 6.0.3・js-yaml 5.4.3 とも同じ)
一重引用符 '…'' を '' と2つ重ねるのが唯一の逃がし。\ と " はそのまま書けるsingle: 'It''s ok' は It's ok
二重引用符 "…"\ で始まる逃がし(\t・\n など)が使える。どんな文字列も書ける唯一の書き方。そのかわり \ と " は逃がす必要があるdouble: "tab\there" は、\t がタブになる

値の頭で特別な意味を持つ記号

値の頭の記号にも決まりがあります。

  • & はアンカー(名前を付ける)、* はエイリアス(名前で呼ぶ)の記号です
  • @ と、バッククォートの記号は、将来のために予約されている記号です

GitHub Actions の文書は、*・[・! は YAML の特殊文字なので、パターンをこれらで始めるときは引用符で囲む、と書いています。フローの並び([ ])の中に [ ] を含むパターンも同じです。文書の例では、- '**/README.md' は正しく、引用符の無い - **/README.md は解析のエラーになり、workflow が動きません。

また、if の式が ! で始まるときは、! が YAML で予約された表記なので、${{ }} で囲むか、''・""・() で逃がします(GitHub の文書より)。

値の一部だけを引用符で囲んでも直らない

値の中に : を含めたいとき、値の一部だけを引用符で囲んでも直りません。 引用符の前が囲まれていないので、全体はプレーンの値のままだからです。

steps:
  - run: echo "a: b"

手元で読ませたファイルには、もう1行 - run: echo a: b も並べていました(一部を省いて載せています)。この run の行は、PyYAML 6.0.3・Docker Compose v5.6.0 では mapping values are not allowed 系、js-yaml 5.4.3 では bad indentation of a mapping entry のエラーになりました(文はあとの「よくあるエラーの読み方」に並べます)。値の全体を囲むか、| で複数行にします。手元では、次の2つの書き方が通りました。

steps:
  - run: 'echo "a: b"'
  - run: |
      echo a: b

PyYAML 6.0.3 の結果は {'steps': [{'run': 'echo "a: b"'}, {'run': 'echo a: b\n'}]} で、js-yaml 5.4.3 でも同じ中身になりました。

複数行の文字列はどう書く?(リテラルと折りたたみ)

複数行の文字列には、2つの書き方があります。

  • |(リテラル): 改行をそのまま残します
  • >(折りたたみ): 改行を空白に変えます。ただし、空行と、さらに字下げした行の改行は別の扱いです

最後の改行の扱い(chomping)は、記号のあとに付ける印で決まります。

  • 何も付けない(clip): 最後の改行を1つ残し、後ろの空行は捨てます
  • -(strip): 最後の改行も、後ろの空行も捨てます
  • +(keep): 最後の改行も、後ろの空行も残します

手元で読ませた YAML です。

literal: |
  line1
  line2
folded: >
  line1
  line2
literal_strip: |-
  line1
  line2
folded_strip: >-
  line1
  line2
literal_keep: |+
  line1
  line2

last: end

PyYAML 6.0.3・js-yaml 5.4.3 のどちらでも、結果は次のとおりでした(Python の書き方での表示です)。

{'literal': 'line1\nline2\n', 'folded': 'line1 line2\n', 'literal_strip': 'line1\nline2', 'folded_strip': 'line1 line2', 'literal_keep': 'line1\nline2\n\n', 'last': 'end'}

\n は改行を表します。literal_keep は、line2 の後ろの空行が残って、\n が2つ続いています。

GitHub Actions で複数行のコマンドを書くときは、run: | を使います。GitHub の文書は、複数行のコマンドは各行が同じシェルで実行される、と書いています。

- run: |
    npm ci
    npm run build

二重引用符の中に \n を書いて、改行を入れる方法もあります。

数や true/false に化ける値は?(1.10・yes/no・on/off)

引用符で囲まない値(プレーン)は、書き方を決まった形(正規表現)に当てはめて、型(数・真偽値・null)が決まります。どれにも当たらなければ文字列です。真偽値は true か false のどちらかの値、null は「値が無い」ことを表す値です。

つまり、文字列のつもりで書いた 1.10 や yes が、数や真偽値として読まれることがあります。しかも、どの形が真偽値や数になるかは、YAML の版とパーサーで違います。

版番号の 1.10 が 1.1 になる

YAML 1.2 の仕様では、パーサーが特に言われない限り使うべき既定の型の決め方(Core スキーマ)があります。そこでは、1.10 は数(float)の形に当たります。数としては 1.1 なので、版番号を 1.10 と書くと 1.1 になります。 文字列にしたいときは "1.10" と囲みます。

手元の PyYAML 6.0.3・js-yaml 5.4.3 では、どちらも次のようになりました。

version_plain: 1.10
version_quoted: "1.10"
python: [3.9, 3.10, "3.10"]

version_plain は 1.1、version_quoted は '1.10'、python は [3.9, 3.1, '3.10'] です。

同じ書き方を、GitHub Actions の workflow の python-version の並びでも試しました。actions/setup-python の文書の例は、版を引用符で囲んでいます(python-version: ['3.9', '3.10', '3.11', 'pypy3.9'])。囲まずに [3.9, 3.10] と書くと、PyYAML 6.0.3・js-yaml 5.4.3 では [3.9, 3.1] になりました。GitHub の上でどう扱われるかは、この記事では確かめていません。 手元で確かめたのは、パーサーに読ませた結果までです。

yes・no・on・off は真偽値になるのか

YAML 1.2 の Core スキーマで真偽値になるのは、true・True・TRUE・false・False・FALSE だけです。

一方、YAML 1.1 の型の一覧(YAML tag repository の bool。2005年1月18日付の作業案)では、yes・no・on・off(大文字の混ぜ方の違いも)と、y・n も真偽値です。このため、国コードのつもりで書いた NO のような値が、false として読まれることがあります(手元の country: NO で確かめます)。

手元で、同じ YAML を3通りの読み方で読ませました。

answers: [yes, no, on, off, y, n, Yes, NO, true, false, True]
country: NO
書いた値PyYAML 6.0.3js-yaml 5.4.3(既定)js-yaml 5.4.3(YAML11_SCHEMA を渡した)
yesTrue文字列 "yes"true
noFalse文字列 "no"false
onTrue文字列 "on"true
offFalse文字列 "off"false
y文字列 'y'文字列 "y"true
n文字列 'n'文字列 "n"false
NO(country: NO)False文字列 "NO"false
trueTruetruetrue

読み取れることは、次のとおりです。

  • PyYAML 6.0.3(YAML 1.1 のパーサー)は、yes・no・on・off を真偽値にしました。ただし y と n は文字列のままで、1.1 の型の一覧とは違いました。「YAML 1.1 のパーサーは、y・n までみな真偽値にする」とは言えません
  • js-yaml 5 の load() は、YAML 1.2 の CORE_SCHEMA を使います(4 系からの移行の文書より)。そのため、既定では yes・no は文字列のままです
  • 1.1 の型や、少し違う数・真偽値の書き方が要るときは、js-yaml 5 に YAML11_SCHEMA を渡します。手元では、渡すと yes も y も true になりました

同じ YAML でも、読むパーサーで値が変わります。真偽値のつもりなら true・false、文字列のつもりなら "yes" のように、はっきり書くのが確実です。

0 から始まる数・60進数・日付

YAML 1.1 の型の一覧には、次のような決まりもあります。

  • 頭に 0 が付いた数は 8進数です
  • : を使うと60進数になります(時刻や角度のため)

手元の結果では、次のように読み方が分かれました。

書いた値PyYAML 6.0.3js-yaml 5.4.3(既定)js-yaml 5.4.3(YAML11_SCHEMA を渡した)
0108108
01238312383
0o10文字列 '0o10'8文字列 "0o10"
22:221342(60進数)文字列 "22:22"1342
1_0001000文字列 "1_000"1000
1e3文字列 '1e3'1000文字列 "1e3"
2026-10-14日付(datetime.date(2026, 10, 14))文字列 "2026-10-14""2026-10-14T00:00:00.000Z"(JSON にしたときの表示)

0123 のような先頭が 0 の数字の並びが 83 に、22:22 のような : でつないだ数字が 1342 に化けるのは、1.1 の決まりで読んだときです。数としては扱いたくない数字の並びは、"0123" のように囲みます。

Docker Compose の場合:文書と手元の結果が違う

Docker の文書には、次の2つの注意があります。

  • environment で真偽値(true・false・yes・no)を書くときは、YAML のパーサーに True・False に変えられないよう、引用符で囲む
  • ports の HOST:CONTAINER は、YAML の60進数とぶつからないよう、いつも(引用符で囲んだ)文字列で書く

手元の Compose に、次の compose.yaml を読ませました。docker compose config は、YAML を読んで Compose が解釈した結果を出すだけのコマンドで、コンテナは作りません。

services:
  web:
    image: nginx:alpine
    environment:
      SHOW: yes
      SHOW_QUOTED: "yes"
      DEBUG: true
      APP_VERSION: 1.10
      APP_VERSION_QUOTED: "1.10"
      ZIP: 0123
    ports:
      - 22:22
      - "8080:80"

Compose v5.6.0 の結果のうち、environment と、1つ目の ports の部分です(ほかの行は省いています)。

    environment:
      APP_VERSION: "1.1"
      APP_VERSION_QUOTED: "1.10"
      DEBUG: "true"
      SHOW: 'yes'
      SHOW_QUOTED: 'yes'
      ZIP: "83"
    ports:
      - mode: ingress
        target: 22
        published: "22"
        protocol: tcp
  • yes は文字列 'yes' のまま、true は文字列 "true" のまま残りました。22:22 も60進数にならず、target: 22・published: "22" になりました
  • 一方、1.10 は "1.1"、0123 は "83" に変わりました
  • Docker Desktop に入っていた v2.38.2-desktop.1 でも同じ値でした(SHOW の引用符の種類だけが違いました)

文書は囲むよう書いていて、手元の版は、yes は文字列のまま、22:22 は60進数になりませんでした。ただし、1.10 と 0123 は囲まないと値が変わりました。 手元の結果は、この2つの版でそうなった、というだけです。この記事は、文書の勧めのとおり、囲む書き方を勧めます。

environment は、リスト(- SHOW=true)でも、キーと値(SHOW: "true")でも書けます。公式の例は、キーと値の書き方では SHOW: "true" と囲んでいます。

GitHub Actions の on: と PyYAML

workflow の on: は、いつ workflow を動かすかを決めるキーです(例: on: push、on: [push, fork])。

手元では、PyYAML 6.0.3(YAML 1.1)で workflow を読むと、on のキーが True になりました({'name': 'CI', True: {'push': {'branches': ['main']}}, ...})。js-yaml 5.4.3 の既定では "on" のままでした。

これは、PyYAML で workflow を読んだときの話です。GitHub の上で workflow がどう読まれるかとは別の話で、GitHub の公式の書き方は on: です。GitHub の公式の例も、引用符なしで on: と書いています。

よくあるエラーの読み方(エラーの文から引く)

YAML のエラーの文は、同じまちがいでも、パーサーと版で文が違います。 この節の文は、すべて手元で出したものです。それぞれ、出したものの名前と版を一緒に書きます。

  • PyYAML 6.0.3 には、2つの読み方があります。Python だけで書かれた SafeLoader(yaml.safe_load() が使う)と、C で書かれた libyaml を使う CSafeLoader です。同じ PyYAML 6.0.3 でも、文が違います(例: mapping values are not allowed here と mapping values are not allowed in this context)。2つは別のエラーではなく、同じまちがいへの別の言い方です
  • js-yaml 5.4.3 は、load() の既定のスキーマで読ませました
  • Docker Compose は、docker compose config に読ませました。v5.6.0 は go-yaml load error in scanner at L2.C15: のような前置きが付き、v2.38.2-desktop.1 は yaml: line 2: の形でした。Docker Desktop に入っている Compose は、最新の v5.6.0 とは限らないので、手元の文が、読む人の環境の文と同じとは限りません

まず早見表

以下の出力は、空行や場所の行などを省いたものがあります。

まちがいPyYAML 6.0.3 SafeLoaderPyYAML 6.0.3 CSafeLoaderjs-yaml 5.4.3Compose v5.6.0
値に : を入れたmapping values are not allowed heremapping values are not allowed in this contextbad indentation of a mapping entrymapping values are not allowed in this context
字下げにタブを使ったfound character '\t' that cannot start any tokenfound character that cannot start any tokentab characters must not be used in indentationfound character that cannot start any token
字下げが半端に浅いexpected <block end>, but found '<block mapping start>'did not find expected keybad indentation of a mapping entrydid not find expected key
キーが1段深いmapping values are not allowed heremapping values are not allowed in this contextbad indentation of a mapping entrymapping values are not allowed in this context
リストの中に - の無いキーexpected <block end>, but found '?'did not find expected '-' indicatorbad indentation of a mapping entrydid not find expected '-' indicator
引用符の閉じ忘れfound unexpected end of streamfound unexpected end of streamdeficient indentationfound unexpected end of stream
同じキーを2回エラーにならない(後の値)エラーにならない(後の値)duplicated mapping keymapping key "name" already defined at line 1
値の頭に *found undefined alias 'feature'found undefined aliasunidentified alias "feature"unknown anchor 'feature' referenced
値の一部だけ引用符mapping values are not allowed heremapping values are not allowed in this contextbad indentation of a mapping entrymapping values are not allowed in this context

js-yaml 5.4.3 は、字下げ・記号まわりの多くのまちがいを bad indentation of a mapping entry と言います。文だけでは、まちがいの種類までは決まりません。

文の中の言葉(<block end> や while parsing a block mapping など)の意味は、PyYAML・js-yaml の文書に説明を見つけられませんでした。 この記事では、どのまちがいのときに、どの文が出て、どこを指したか、までを書きます。

エラーの場所の読み方

  • PyYAML: in "ファイル名", line 2, column 15 の形で、行と桁を出します。手元では、次の message: Error: file not found の例で、2行目の15文字目(2つ目の :)を指しました。文字列を yaml.safe_load() に渡して読むと、場所の下に、その行の抜き出しと ^ の印も付きました(ファイルを渡したときは付きませんでした)
  • js-yaml: (2:15) の形で、行と桁を出し、その行の抜き出しと ^ の印を付けます
  • Compose: v5.6.0 は L2.C15(2行目15桁)、v2.38.2 は line 2 のように、行だけを出しました

場所が2つ出ることがあります。たとえば、字下げが半端に浅い例(下の「did not find expected key」)では、PyYAML の1つ目の場所(while parsing a block mapping のあと)は web: の位置(2行目3列)、2つ目は字下げがずれた ports: の位置(4行目4列)を指しました。Compose v2.38.2 は line 1 だけを出し、おかしい4行目を指しませんでした。出た行だけでなく、その前後の字下げも見ます。

mapping values are not allowed(here / in this context)

3つのまちがいで、この文が出ました。

① 引用符で囲まない値の中に : がある

name: build
message: Error: file not found
[PyYAML 6.0.3 SafeLoader]
mapping values are not allowed here
  in "e01-mapping-values.yaml", line 2, column 15

[PyYAML 6.0.3 CSafeLoader]
mapping values are not allowed in this context
  in "e01-mapping-values.yaml", line 2, column 15

[js-yaml 5.4.3]
bad indentation of a mapping entry in "e01-mapping-values.yaml" (2:15)

[Compose v5.6.0]
go-yaml load error in scanner at L2.C15: mapping values are not allowed in this context

[Compose v2.38.2-desktop.1]
yaml: line 2: mapping values are not allowed in this context

直し方は、値の全体を引用符で囲むか、| の複数行で書くことです。

② キーを1段深く字下げした

services:
  web:
    image: nginx
      ports:
      - "8080:80"

image: nginx の下で、ports: だけが深く下がっています。PyYAML 6.0.3 の SafeLoader は4行目12列を指して mapping values are not allowed here、CSafeLoader と Compose v5.6.0(L4.C12)は mapping values are not allowed in this context、js-yaml 5.4.3 は bad indentation of a mapping entry(場所は (4:12))でした。直し方は、同じ階層のキーの字下げを揃えることです。

③ 値の一部だけを引用符で囲んだ

前の「文字列と引用符」の - run: echo "a: b" です。PyYAML 6.0.3 の SafeLoader は2行目17列を指して mapping values are not allowed here、js-yaml 5.4.3 は bad indentation of a mapping entry(場所は (2:17))、Compose v5.6.0 は go-yaml load error in scanner at L2.C17: mapping values are not allowed in this context でした。直し方は、値の全体を囲むか、| で書くことです。

found character that cannot start any token

字下げにタブを使ったときに出ました。次の YAML の2行目の頭は、タブ1文字です(→ がタブを表します)。

services:
→web:
    image: nginx
[PyYAML 6.0.3 SafeLoader]
while scanning for the next token
found character '\t' that cannot start any token
  in "e02-tab.yaml", line 2, column 1

[PyYAML 6.0.3 CSafeLoader]
found character that cannot start any token

[js-yaml 5.4.3]
tab characters must not be used in indentation in "e02-tab.yaml" (2:1)

[Compose v5.6.0]
go-yaml load error in scanner (while scanning for the next token) at L2.C1: found character that cannot start any token

見た目は空白と同じなので、気づきにくいまちがいです。直し方は、タブを空白に置き換えることです。エディターの Tab キーが空白を入れる設定にしておくと、防げます。

この文は、値の頭が @ や、バッククォートの記号のときにも出ました(user: @alice など)。どちらも予約された記号なので、値を引用符で囲みます。PyYAML 6.0.3 の SafeLoader は found character '@' that cannot start any token、js-yaml 5.4.3 は、このときも bad indentation of a mapping entry でした。

did not find expected key

字下げが、上のキーより浅く、親より深い半端な位置になっているときに出ました。

services:
  web:
    image: nginx
   ports:
    - "8080:80"

image: は空白4つ、ports: は空白3つです。

[PyYAML 6.0.3 SafeLoader]
while parsing a block mapping
  in "e04-indent-less.yaml", line 2, column 3
expected <block end>, but found '<block mapping start>'
  in "e04-indent-less.yaml", line 4, column 4

[PyYAML 6.0.3 CSafeLoader]
while parsing a block mapping
  in "e04-indent-less.yaml", line 2, column 3
did not find expected key
  in "e04-indent-less.yaml", line 4, column 4

[js-yaml 5.4.3]
bad indentation of a mapping entry in "e04-indent-less.yaml" (4:4)

[Compose v5.6.0]
go-yaml load error in parser (while parsing a block mapping) at L2.C3-L4.C4: did not find expected key

[Compose v2.38.2-desktop.1]
yaml: line 1: did not find expected key

PyYAML 6.0.3 の SafeLoader だけが expected <block end>, but found '<block mapping start>' と言い、CSafeLoader と Compose は did not find expected key と言いました。直し方は、同じ階層のキーの字下げを揃えることです。

did not find expected '-' indicator

リスト(- name: ... の並び)と同じ字下げに、- の無いキーを置いたときに出ました。

steps:
  - name: checkout
    uses: actions/checkout@v6
  name: test
[PyYAML 6.0.3 SafeLoader]
while parsing a block collection
  in "e06-list-then-key.yaml", line 2, column 3
expected <block end>, but found '?'
  in "e06-list-then-key.yaml", line 4, column 3

[PyYAML 6.0.3 CSafeLoader]
did not find expected '-' indicator

[js-yaml 5.4.3]
bad indentation of a mapping entry in "e06-list-then-key.yaml" (4:3)

[Compose v5.6.0]
go-yaml load error in parser (while parsing a block collection) at L2.C3-L4.C3: did not find expected '-' indicator

PyYAML 6.0.3 の SafeLoader は expected <block end>, but found '?' と言いました。直し方は、リストの項目なら - を付けること、前の項目のキーなら、- のあとの字下げに揃えることです(上の例なら、name: test を - name: test にします)。

found unexpected end of stream

引用符を閉じ忘れたときに出ました。

name: "hello
version: 1

PyYAML 6.0.3 は SafeLoader・CSafeLoader とも while scanning a quoted scalar(1行目7列)のあと、found unexpected end of stream(3行目1列)と言いました。Compose v5.6.0 も同じ文(at L1.C7-L3.C1)で、js-yaml 5.4.3 は deficient indentation(場所は (2:1))でした。直し方は、引用符を閉じることです。

found undefined alias(unknown anchor)

値の頭の * が、エイリアス(アンカーに付けた名前を呼ぶ記号)として読まれたときに出ました。GitHub Actions のパターンの書き方で起きます。

on:
  push:
    branches: [*feature]

PyYAML 6.0.3 の SafeLoader は found undefined alias 'feature'(3行目16列)、CSafeLoader は found undefined alias、js-yaml 5.4.3 は unidentified alias "feature"(場所は (3:17))、Compose v5.6.0 は go-yaml load error in composer at L3.C16: unknown anchor 'feature' referenced でした。直し方は、['*feature'] のように引用符で囲むことです。

duplicated mapping key(同じキーを2回書いた)

name: first
name: second
  • js-yaml 5.4.3 は duplicated mapping key in "e08-duplicate-key.yaml" (2:1) とエラーにしました
  • Compose は mapping key "name" already defined at line 1 とエラーにしました(v5.6.0 は yaml: construct errors:、v2.38.2 は yaml: unmarshal errors: のあとに出ました)
  • PyYAML 6.0.3 は、エラーにしませんでした。 後の値が残り、{'name': 'second'} になりました

仕様は、キーと値の組の中で、キーは重ねてはいけないと書いています。重ねたときの動きがパーサーで違うので、どちらかを消します。

TypeError: load() missing 1 required positional argument: 'Loader'

PyYAML 6.0.3 で Loader を渡さずに yaml.load() を呼んだときに出ます。

$ python -c "import yaml; yaml.load('a: 1')"   # 出力の最後の1行だけを載せています
TypeError: load() missing 1 required positional argument: 'Loader'

PyYAML の変更履歴には、6.0(2021年10月13日)で yaml.load() に Loader を必ず渡す形にした、とあります。ふつうは yaml.safe_load() を使います。

PyYAML の文書は、信用できない所から受け取ったデータに yaml.load を使うのは安全ではない、と警告しています。yaml.load は pickle.load(Python のオブジェクトを保存・復元する標準の仕組み)と同じくらい強く、どんな Python の関数も呼べるためです。外から来た YAML は yaml.safe_load() で読みます。これは PyYAML の load の話で、YAML というデータの書き方そのものが危険、という意味ではありません。

エラーにならずに意味が変わるまちがい

エラーが出ないまちがいもあります。エラーが出ないので、読み込んだ結果を見て確かめます。

  • : や - のあとの空白を忘れる: 手元では、name:hello と port:8080 の2行が、1つの文字列 'name:hello port:8080' になりました。-apple と -banana は {'fruits': '-apple -banana'} になりました(PyYAML 6.0.3・js-yaml 5.4.3 とも同じ)。仕様は、: や - は、あとに空白でない文字が続くときは、頭の文字にもなれる、と書いています
  • 1.10 が 1.1 になる、yes が True になる、0123 が 83 になる: 前の節のとおりです
  • 同じキーを2回書く: PyYAML 6.0.3 は後の値を取ります(上のとおり)

GitHub Actions と compose.yaml を読んでみる

ここまでの決まりで、実際のファイルの形を読みます。字下げと記号の読み方の練習です。

GitHub Actions の workflow

次は、手元のパーサーに読ませた workflow です(python-version の3つ目だけ囲んであるのは、前の節の確かめのためです)。

name: CI
on:
  push:
    branches: [main]
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: [3.9, 3.10, "3.11"]
    steps:
      - uses: actions/checkout@v6
      - run: echo hello

字下げで読むと、次のようになります。

  • 一番左の name・on・jobs が、最上位のキーです
  • on: の下の push:、その下の branches: [main] は、入れ子です。[main] は流れの書き方のリストです。on は、workflow をいつ動かすかを決めます
  • steps: の下の - uses: ... と - run: ... は、リストの項目です。- のあとの空白と、そのあとのキーの字下げが揃っている必要があります(揃っていないとエラーになります。出る文はパーサーで違います)

jobs・steps・uses などの意味と、権限の設定は、GitHub Actions の記事で説明しています。

公式の例の checkout は、actions/checkout@v6 です。GitHub の文書には、version: [10, 12, 14] のように、matrix の値を引用符なしの数で書く例もあります(actions/setup-node@v7 の node-version に渡します)。これは整数なので、1.10 が 1.1 になる話とは違います。

compose.yaml とアンカー

Compose では、YAML のアンカー(&)とエイリアス(*)で、くり返す設定を1か所にまとめられます。一部を上書きするときは、YAML のマージ(<<)の決まりに従います。Docker の文書は、マージはキーと値の組にだけ使え、リストには使えない、と書いています。

x-common: &common
  image: nginx:alpine
  restart: always
services:
  web:
    <<: *common
    ports:
      - "8080:80"
  web2: *common

&common で名前を付けた設定を、<<: *common で取り込み、web2: *common でそのまま使っています。Compose v5.6.0 の docker compose config では、web に image と restart が入りました(先頭の name・networks・x-common の行は省いています)。

services:
  web:
    restart: always
    image: nginx:alpine
    ports:
      - mode: ingress
        target: 80
        published: "8080"
        protocol: tcp
  web2:
    restart: always
    image: nginx:alpine

PyYAML 6.0.3 も << をマージしました。js-yaml 5.4.3 は、既定では << を扱わず、<< がそのままキーとして残りました("web":{"<<":{"image":"nginx:alpine","restart":"always"},"ports":["8080:80"]})。js-yaml の移行の文書は、これを「いちばんよくある互換の違い」と書き、CORE_SCHEMA.withTags(mergeTag) で足せると説明しています。

ports は、Docker の公式の例がすべて引用符で囲んでいます(- "8000:8000"・- "49100:22" など)。volume の短い書き方(コロン区切り)は、Docker の volume と bind mount の違い|どっちを使う?書き方とデータが消える原因で説明しています。

よくある質問

YAML の読み方は?

YAML 1.2.2 の仕様の冒頭に、「YAML は camel(キャメル)と韻を踏む」と書かれています。カタカナでの読みは、仕様には書かれていません。

.yml と .yaml はどちらを使えばいいですか?

拡張子の .yaml が推奨で、.yml もまだ使われている、と IETF の RFC 9512(YAML のメディアタイプ。2024年2月)に書かれています。同じ場所に config.yaml と config.yml が両方あると困ることがある、とも書かれています。

道具ごとの決まりは、次のとおりです。

  • GitHub Actions の workflow は、.yml か .yaml のどちらも使えます
  • Docker Compose は、compose.yaml が推奨で、compose.yml も読みます。古い版との互換のための docker-compose.yaml・docker-compose.yml も読み、compose.yaml と両方あれば compose.yaml を使います

コメントアウトのしかたは?複数行は?

# から行の終わりまでがコメントです。複数行をコメントにしたいときは、各行の頭に # を付けます。YAML 1.2.2 の仕様のコメントの節には、# 以外の書き方は見つかりませんでした。複数行を囲む書き方が無い、とまでは、この記事では言い切りません。

インデントのエラーの場所がわからないときは?

エラーの文に出る行と桁は、まちがいの場所そのものとは限りません。字下げが半端に浅い例(did not find expected key)では、PyYAML 6.0.3 が web: の位置(2行目)と、字下げがずれた ports: の位置(4行目)の2か所を出し、Compose v2.38.2 は、おかしい4行目ではなく line 1 を出しました。出た行だけでなく、その前後の字下げも見ます。 字下げにタブが混ざっていないかも確かめます。

書いた YAML のエラーをチェックするには?

使っているパーサーに読ませると、エラーの文と場所が出ます。PyYAML なら yaml.safe_load()、js-yaml なら load() に読ませます。Docker Compose なら、次のコマンドで読ませられます(コンテナは作りません)。

docker compose -f compose.yaml config

エラーにならない書き方のまちがい(1.10 が 1.1 になるなど)は、読み込んだ結果を見て確かめます。特定のチェックの道具やサイトは、この記事では調べていないので、勧めません。

まとめ

  • YAML は、字下げで入れ子を書く、人が読み書きしやすいデータの書き方で、「YAML Ain't Markup Language」の略です。GitHub Actions の workflow や Docker Compose の設定ファイルによく使われます。最新の仕様は YAML 1.2.2 で、PyYAML は YAML 1.1、js-yaml 5 は YAML 1.2 のパーサーです
  • 基本の記号は、キーと値の : 、リストの - 、コメントの # で、そのあとの空白が決まりの一部です。字下げにタブは使えません。同じ階層の字下げは揃えます
  • 値の中に : を入れたいときは、値の全体を引用符で囲むか、| の複数行で書きます。一部だけを囲んでも直りません。文字列として *・@・バッククォートで始めたい値や、GitHub Actions のパターン(*・[・! で始まるもの)は、囲みます
  • 引用符で囲まない値は、1.10 → 1.1、yes → True(PyYAML 6.0.3)、0123 → 83 のように、数や真偽値として読まれることがあります。どう読まれるかは、YAML の版とパーサーで違います。文字列にしたい値は、囲みます
  • Docker Compose の文書は、真偽値の言葉と ports の HOST:CONTAINER を囲むよう書いています。手元の v5.6.0・v2.38.2 では、yes は文字列のまま、22:22 は60進数になりませんでしたが、1.10 と 0123 は変わりました。この記事は、文書の勧めのとおり、囲む書き方を勧めます
  • エラーの文は、同じまちがいでも、パーサーと版で違います。文を調べるときは、出したものの名前と版を確かめます。PyYAML 6.0.3 は SafeLoader と CSafeLoader で文が違い、js-yaml 5.4.3 は多くを bad indentation of a mapping entry と言います
  • エラーにならずに意味が変わるまちがい(空白の忘れ、同じキーを2回書く(PyYAML では)、1.10)は、読み込んだ結果を見て確かめます
  • PyYAML では、外から来たデータを読むときは yaml.safe_load() を使います
  • この記事の出力例は、PyYAML 6.0.3・js-yaml 5.4.3・Docker Compose v5.6.0 と v2.38.2-desktop.1(macOS)のものです。GitHub の上と Windows では流していません

参考資料

この記事は、次の公式の資料をもとに書きました(2026年10月14日時点)。

※この記事は、公式の資料をもとに AI(Claude)で下書きし、2026年10月14日時点の公式の資料と照らして確かめてから公開しています。誤りに気づいたらお問い合わせからお知らせください。

PR
PR
タイトルとURLをコピーしました