YAML Error Did Not Find Expected Key and How to Fix It
Why a line indented between two levels raises did not find expected key, how PyYAML words it differently, and how to realign. Output from three parsers.

Of the YAML errors that confuse people, this one has the most variety in wording. The same mistake produces "did not find expected key" in one tool and "expected block end, but found block mapping start" in another. Both describe the same situation: a line is indented to a column that does not match any level that is open at that point. This post shows the mistake, the three wordings, and a method for fixing it that does not rely on the message.
The mistake
A mapping has a block of keys at one indentation. A key written between two levels belongs to neither:
a:
b: 1
c: 2b is indented four spaces under a. c is indented two. Two is more than zero, so it is not a top-level key, and less than four, so it is not a sibling of b. There is no open block at column 2, and the parser has nowhere to put it. A realistic version is a Compose file:
services:
web:
image: x
ports:
- 80ports is at three spaces, between web (two) and image (four). Same situation.
Three wordings, one error
CSafeLoader (libyaml): while parsing a block mapping | in "k1.yaml", line 1, column 1 | did not find expected key | in "k1.yaml", line 3, column 3
yq (Go) : go-yaml load error in parser (while parsing a block mapping) at L1.C1-L3.C3: did not find expected key
PyYAML (pure Python) : while parsing a block mapping | expected <block end>, but found '<block mapping start>' | line 3, column 3The first two are the C library libyaml and a Go port of it. The third is PyYAML's own Python implementation, which uses different wording for the same state. In all three the position is line 3, column 3, the start of c. The "while parsing a block mapping" context starts at line 1, column 1, the start of the mapping whose block was open.
For the Compose-style file, the position is line 4, column 4 and the context line 2, column 3:
while parsing a block mapping | in "k2.yaml", line 2, column 3 | did not find expected key | in "k2.yaml", line 4, column 4The context says where the open block began (the web mapping at line 2), and the error says which line does not belong (line 4, the ports line). Read both: the context tells you which level the misplaced line should have matched.
Note that PyYAML defaults to the pure Python loader in safe_load when the C extension is not used. If you want the libyaml wording, use yaml.load(stream, Loader=yaml.CSafeLoader) when available. This is only about the text: results and positions are the same.
How to fix it without decoding the message
Go to the reported line. Find the first character of its key, and note its column.
Look at the lines above it, upward until you find one with the same intended level. For
ports, that isimage, whose key starts in column 5. Forc, it was meant to be a sibling ofa, at column 1.Make the indentation identical. Add or remove spaces. Do not change the lines above.
Reload and print the structure.
A mnemonic: the line you were told about is the one that needs to move. The parser reports the line where it gave up, which is the offender here (unlike the "mapping values" error, where the reported line is often one after the real mistake).
If you are not sure which level was intended, the structure of the data decides. A ports key under a service is a key of that service, so it belongs next to image. In a list of items, the keys of one item are aligned with the first key, which starts two columns after the dash.
A variant: list items
The same error appears with lists whose items are aligned wrongly:
- name: a
v: 1
-name: bThe third line starts one space in and is a stray text, and the message shows a related wording, "while parsing a block collection ... expected block end, but found block mapping start", at line 3. The fix is to align the dash with the others, at column 1, and put a space between the dash and the key: - name: b. A dash without a following space is not a list indicator at all.
Why linters help
yamllint is useful beyond syntax errors because it reports indentation faults with their own rule names. On a file with mixed indentation it printed lines like wrong indentation: expected 2 but found 4 and wrong indentation: expected 4 but found 0, along with the one syntax error. The messages tell you what the linter expected at each line, which is the quickest way to learn the intended structure (fixing YAML indentation errors with a linter). In an editor with indent guides (vertical lines at each level), a key between two guides is visible immediately.
When a team's files are generated or reformatted by a tool, this error means a bug in the tool or a hand edit after generation. Reformat with the tool again, and diff.
Preventing it
The error is almost always the result of an edit in the middle of a file. Three habits stop it. Edit with an editor that re-indents blocks as a unit: selecting a block and pressing Tab or Shift-Tab moves every line by the same amount, where adding spaces to individual lines is how a line ends up between levels. Keep indentation at two spaces everywhere, so there are no "in between" columns that look plausible: with a single width, a line either matches a level or visibly does not. And reformat the file after large edits, with a formatter that parses and rewrites it, which turns any accidental alignment into the canonical one or fails loudly.
For files edited by several people, a pre-commit hook that parses every staged YAML file stops this error from reaching the repository. The check is one line, and it costs milliseconds. A parse that fails in the hook produces the same message and position you would see later, but on the developer's machine, minutes after the edit, when the cause is obvious.
Related reading
The cluster hub is fixing YAML errors that make no sense. Sibling errors: mapping values are not allowed here and could not find expected colon. For the structure rules, read YAML indentation rules and why tabs break everything. The parser stages are described in the YAML 1.2.2 specification, chapter 9 and libyaml's messages in its source repository. Inspect the repaired file in the YAML formatter.
When the message hides a different mistake
A quote or bracket is open above. An unclosed quote earlier in the file changes how the following lines are read. If realigning does not help, look for a missing closing quote or bracket.
The file mixes block and flow style incorrectly. A flow collection that is not closed makes later lines look like extra keys.
A tab is involved. A tab in the indentation of one line changes its apparent column. Check for tabs.
The file was concatenated. Two YAML files pasted together without a document separator end up with duplicate top-level keys or misaligned blocks. Separate them with three dashes or merge them properly (merging YAML files from the command line).


