---
title: "YAML front matter nested keys: three pandoc readers tested"
slug: yaml-front-matter-nested-keys
excerpt: "Pandoc output for yaml front matter nested keys is reported in Three readers on the nested file."
quickAnswer: "The section Sample header and printing template sets out the test header next to its template. Under Three readers on the nested file, the commands sit beside the lines pandoc printed. Under A child key moved to column zero, a header with team pulled out of owner is run and its output quoted. The section A child key indented too far quotes the error pandoc wrote for an over-indented key. The section One tab before the name key shows the tab file, its run and the control count. Under Steps to check a nested header, the checks are laid out as numbered steps."
keyTakeaways:
  - "Input lines plus template syntax appear in Sample header and printing template."
  - "Output for markdown, commonmark_x plus commonmark+yaml_metadata_block is reported in Three readers on the nested file."
  - "What happened when team moved out of owner is shown in A child key moved to column zero."
  - "The error lines from the over-indented file sit in A child key indented too far."
  - "Look at Steps to check a nested header for commands you can point at a file of yours."
publishedDate: 2026-10-21
dateModified: 2026-10-21
author: Bobby Huang
cluster: B
role: post
status: published
faq:
  - q: Why is my nested value empty?
    a: "Compare your header with the run in A child key moved to column zero."
  - q: Why did pandoc stop with a YAML parse exception?
    a: "The run that stopped is quoted in A child key indented too far."
  - q: Can a tab indent a nested key?
    a: "See One tab before the name key for what pandoc did in the test."
  - q: How do I print a nested value from the header?
    a: "Dotted template lines appear under Sample header and printing template."
related:
  - yaml-front-matter-errors
  - yaml-front-matter-in-markdown
  - front-matter-fields-status-date-owner
---

On this page, yaml front matter nested keys are keys typed under a parent key in the YAML header of a Markdown file, set in below that parent. I built one header with two parent keys, `owner` and `review`, and asked pandoc 3.8.3 to print the values stored under them. Three reader settings took part: `markdown`, `commonmark_x`, plus `commonmark+yaml_metadata_block`.

After that, I changed the indent three ways and ran the same readers again. Each command got a single pass on macOS. Results quoted here come word for word from the test log, line breaks included.

## Sample header and printing template

`nested.md` is the starting file. The log counts it at 13 lines:

```markdown
---
title: Doe plan
owner:
  name: Jane Doe
  team: Doe Holdings
review:
  by: John Doe
  steps:
    - read
    - sign
---

Body line.
```

Two keys sit under `owner` and two sit under `review`. Under `review`, `steps` carries a two-item list.

A small template file, `nested-tpl.html`, took the place of pandoc's default page so the stored values would print:

```html
name=[$owner.name$]
team=[$owner.team$]
by=[$review.by$]
steps=[$for(review.steps)$$review.steps$;$endfor$]
```

In this template, a dotted path like `$owner.name$` reaches into a parent key for its value. The `$for(review.steps)$` and `$endfor$` pair repeats the text between them once per list item. The `;` after `$review.steps$` is plain template text that marks where one item stops. Each bracket pair is plain text too. They show where a printed value starts and ends, so a missing value shows up as `[]`.

## Three readers on the nested file

From the test folder, one command per reader:

```sh
pandoc -f markdown -s --template nested-tpl.html -t html nested.md
pandoc -f commonmark+yaml_metadata_block -s --template nested-tpl.html -t html nested.md
pandoc -f commonmark_x -s --template nested-tpl.html -t html nested.md
```

Pandoc's `markdown` reader left four value lines in the log, and the script recorded the exit code after them:

```text
name=[Jane Doe]
team=[Doe Holdings]
by=[John Doe]
steps=[read;sign;]
rc=0
```

Each commonmark-based run gave back those identical five lines. Both child keys under `owner` came through, `review.by` came through, and the loop wrote `read` and then `sign`, the order they have in the file.

Why does the second reader carry `+yaml_metadata_block`? Pandoc's own extension lists answer that. For `markdown`, `+yaml_metadata_block` turns up on line 73 of that list, and `commonmark_x` carries the same entry on line 30. Plain `commonmark` lists `-yaml_metadata_block` at line 30, so this test turned the extension on by name for that reader. The companion post on [multiline strings in YAML front matter](yaml-front-matter-multiline-string.md) includes a plain `commonmark` run where the extension stayed off.

## A child key moved to column zero

The second file, `nested-outdent.md`, is 8 lines long by the log's count. It keeps `name:` two spaces in under `owner:`, while `team:` starts at column 0:

```markdown
---
title: Doe plan
owner:
  name: Jane Doe
team: Doe Holdings
---

Body line.
```

The matching template, `nested-outdent-tpl.html`, asks for the team value in two places, once inside `owner` and once at the top level:

```html
name=[$owner.name$]
owner.team=[$owner.team$]
team=[$team$]
```

The command for the `markdown` reader was:

```sh
pandoc -f markdown -s --template nested-outdent-tpl.html -t html nested-outdent.md
```

Pandoc printed this, and the script added the rc line:

```text
name=[Jane Doe]
owner.team=[]
team=[Doe Holdings]
rc=0
```

Both commonmark-based runs produced those four lines too. Nothing in the log flags a problem: the exit code is 0 and no warning text appears. Even so, `owner.team` came back empty, and Doe Holdings turned up under a top-level key called `team`. Here, that header ran clean with rc 0 even though `team` no longer sat under `owner`.

## A child key indented too far

`nested-overindent.md` also runs to 8 lines in the log. This time `team:` sits four spaces in, two more than `name:` on the line above:

```markdown
---
title: Doe plan
owner:
  name: Jane Doe
    team: Doe Holdings
---

Body line.
```

Pandoc read it against the main template, `nested-tpl.html`:

```sh
pandoc -f markdown -s --template nested-tpl.html -t html nested-overindent.md
```

No values printed this time. Pandoc wrote a three-line error instead. Line one of that error holds the input's full path on the test machine; this page skips it. The other two lines and the logged exit code read:

```text
YAML parse exception at line 4, column 8:
mapping values are not allowed in this context
rc=64
```

The two commonmark-based runs repeat those two lines, with rc 64 again. Set this beside the column-zero file: that header gave rc 0 with one empty value, and this one stopped the whole run before any template line came out.

## One tab before the name key

`nested-tab.md` is 7 lines by the log's count. It has a `title` line and an `owner:` line, and then `name: Jane Doe` pushed in by one tab character where the other files use two spaces. A tab byte can't appear on this page, so the listing below writes it as the placeholder `<TAB>`:

```markdown
---
title: Doe plan
owner:
<TAB>name: Jane Doe
---

Body line.
```

The test script checked the tab with a control step. It counted the lines holding a tab character in two files:

```sh
grep -c "$(printf '\t')" nested-tab.md
grep -c "$(printf '\t')" nested.md
```

Those commands printed `1` for `nested-tab.md` and `0` for `nested.md`. One line of `nested-tab.md` carries a tab, then, while `nested.md` carries zero.

The tab file ran with `nested-tpl.html`:

```sh
pandoc -f markdown -s --template nested-tpl.html -t html nested-tab.md
```

The log holds:

```text
name=[Jane Doe]
team=[]
by=[]
steps=[]
rc=0
```

Under the other two readers, the log shows those five lines again. Pandoc gave Jane Doe for `$owner.name$` from the tab-indented line in this test, with rc 0. The `team`, `by` and `steps` slots stayed empty because this short file never sets those keys. Guidance on tabs and on lining up list items lives in [YAML front matter errors](yaml-front-matter-errors.md).

## Steps to check a nested header

You can run the same kind of check on a header of your own. Swap your file name in for `nested.md` and put your own key paths in the template.

1. Write a template with one line per value you expect. Use dotted names such as `$owner.team$` and wrap each one in brackets.
2. Run the `pandoc` command for the reader you use, with `-s --template` pointing at your template file.
3. Read every bracket pair. In the column-zero run, an empty `[]` beside `owner.team` was the sign that `team` had moved out of `owner`.
4. Check the rc. The over-indented file in this test stopped with rc 64 and printed no values.
5. To find out whether a file has tab characters in it, run the `grep -c` line from the tab section on that file.

What an `owner` field and its sibling keys are meant to hold is covered in [this rundown of front matter fields](front-matter-fields-status-date-owner.md).

## Where Sashmark fits

Two ideas in the design of Sashmark, a desktop app not yet finished, matter for any file you touch. Under the Round-Trip idea, a fix typed into the formatted page would reach the disk when you save, with every other byte left alone. Under the Changes View idea, whatever an agent altered between your visits would carry a mark, in a git repo or in a plain folder.

It is in development and has not been released. The app itself has no AI features. See the [planned features](/features), the [help pages](/help) and the [roadmap](/roadmap) for where each part stands.

More at [sashmark.com](https://www.sashmark.com/).
