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 の別の版も流していません
- YAML とは?何の略で、何に使われる?
- YAML の基本の書き方(キーと値・リスト・入れ子・コメント)
- YAML と JSON・TOML の違いは?
- 文字列と引用符(' と ")の使い分けと、複数行の書き方
- 数や true/false に化ける値は?(1.10・yes/no・on/off)
- よくあるエラーの読み方(エラーの文から引く)
- まず早見表
- エラーの場所の読み方
- mapping values are not allowed(here / in this context)
- found character that cannot start any token
- did not find expected key
- did not find expected '-' indicator
- found unexpected end of stream
- found undefined alias(unknown anchor)
- duplicated mapping key(同じキーを2回書いた)
- TypeError: load() missing 1 required positional argument: 'Loader'
- エラーにならずに意味が変わるまちがい
- GitHub Actions と compose.yaml を読んでみる
- よくある質問
- まとめ
- 参考資料
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つです。
- 仕様が大きい(印刷すると、レターサイズの紙で86ページ)ので、あるパーサーでは動き、別のパーサーでは動かない機能を使ってしまうおそれがある
- YAML は既定では安全ではない(PyYAML には
safe_loadがあるが、道具がうっかりloadを使うと任意のコードが動く) - よく使われる 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.3 | js-yaml 5.4.3(既定) | js-yaml 5.4.3(YAML11_SCHEMA を渡した) |
|---|---|---|---|
yes | True | 文字列 "yes" | true |
no | False | 文字列 "no" | false |
on | True | 文字列 "on" | true |
off | False | 文字列 "off" | false |
y | 文字列 'y' | 文字列 "y" | true |
n | 文字列 'n' | 文字列 "n" | false |
NO(country: NO) | False | 文字列 "NO" | false |
true | True | true | true |
読み取れることは、次のとおりです。
- 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.3 | js-yaml 5.4.3(既定) | js-yaml 5.4.3(YAML11_SCHEMA を渡した) |
|---|---|---|---|
010 | 8 | 10 | 8 |
0123 | 83 | 123 | 83 |
0o10 | 文字列 '0o10' | 8 | 文字列 "0o10" |
22:22 | 1342(60進数) | 文字列 "22:22" | 1342 |
1_000 | 1000 | 文字列 "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 SafeLoader | PyYAML 6.0.3 CSafeLoader | js-yaml 5.4.3 | Compose v5.6.0 |
|---|---|---|---|---|
値に : を入れた | mapping values are not allowed here | mapping values are not allowed in this context | bad indentation of a mapping entry | mapping values are not allowed in this context |
| 字下げにタブを使った | found character '\t' that cannot start any token | found character that cannot start any token | tab characters must not be used in indentation | found character that cannot start any token |
| 字下げが半端に浅い | expected <block end>, but found '<block mapping start>' | did not find expected key | bad indentation of a mapping entry | did not find expected key |
| キーが1段深い | mapping values are not allowed here | mapping values are not allowed in this context | bad indentation of a mapping entry | mapping values are not allowed in this context |
リストの中に - の無いキー | expected <block end>, but found '?' | did not find expected '-' indicator | bad indentation of a mapping entry | did not find expected '-' indicator |
| 引用符の閉じ忘れ | found unexpected end of stream | found unexpected end of stream | deficient indentation | found unexpected end of stream |
| 同じキーを2回 | エラーにならない(後の値) | エラーにならない(後の値) | duplicated mapping key | mapping key "name" already defined at line 1 |
値の頭に * | found undefined alias 'feature' | found undefined alias | unidentified alias "feature" | unknown anchor 'feature' referenced |
| 値の一部だけ引用符 | mapping values are not allowed here | mapping values are not allowed in this context | bad indentation of a mapping entry | mapping 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日時点)。
- YAML 1.2.2 の仕様
- YAML 1.1 の仕様
- YAML 1.1 の型の一覧: bool
- YAML 1.1 の型の一覧: int
- YAML 1.1 の型の一覧: float
- RFC 9512: YAML Media Type
- PyPI: PyYAML
- PyYAML の文書
- PyYAML の変更履歴(CHANGES)
- js-yaml の変更履歴(CHANGELOG)
- js-yaml の README
- js-yaml: 4 系から 5 系への移行
- js-yaml: スキーマの一覧
- GitHub の文書: ワークフロー構文
- actions/setup-python の文書: advanced-usage
- Docker の文書: Compose アプリケーションモデル
- Docker の文書: Compose ファイルの services
- Docker の文書: Compose ファイルの fragments
- Docker Compose の最新のリリース(GitHub)
- PEP 518
※この記事は、公式の資料をもとに AI(Claude)で下書きし、2026年10月14日時点の公式の資料と照らして確かめてから公開しています。誤りに気づいたらお問い合わせからお知らせください。



