Back to Blog
·3 min read·yamlvalidator

YAML errors explained: the ones that break your build — and the ones that never error at all

Real parser output for the five YAML mistakes that fail CI (tabs, unclosed quotes, bad flow, bad indent), plus six values YAML silently mangles — NO becomes false, 12:30:45 becomes 45045. All verified.

YAML failures come in two kinds. The loud kind stops your docker compose up or GitHub Actions run with a parser error and a line number. The quiet kind parses fine, deploys fine, and then your Norwegian users are in country false.

We re-verified everything below against a real parser (PyYAML 6, the engine behind an enormous amount of CI tooling) while writing this — every error message and every mangled value is actual output, not paraphrase.

The loud failures: what the error actually means

"found character '\t' that cannot start any token"

ScannerError: while scanning for the next token
found character '\t' that cannot start any token
  in "<unicode string>", line 2, column 1

You indented with a Tab. YAML forbids tabs in indentation, full stop. This is the classic paste-from-terminal failure: your editor shows what looks like clean nesting, but line 2 column 1 holds \t. Fix: convert tabs to spaces (2 is the convention), and turn on "show invisibles" for YAML files.

"while scanning a quoted scalar … found unexpected end of stream"

ScannerError: while scanning a quoted scalar
  in "<unicode string>", line 1, column 11
found unexpected end of stream

An opened " was never closed. The parser reads to the end of the file looking for the closing quote, so the reported line is where the quote opened — the actual missing character is usually much further down. Fix from the reported column, not from the end of the file.

"while parsing a flow sequence … expected ',' or ']'"

ParserError: while parsing a flow sequence
  in "<unicode string>", line 1, column 8
expected ',' or ']', but got ':'

A flow collection ([80, 443 or {key: value) was never closed before the next mapping started. Common in ports: lists and inline env maps.

"while parsing a block collection … expected <block end>"

ParserError: while parsing a block collection
  in "<unicode string>", line 2, column 3
expected <block end>, but found '<block sequence start>'

Two sibling list items with different indentation — - run: build at two spaces, - run: test at three. The parser thinks the first list ended and something new began. This is the most common hand-edited GitHub Actions failure, because workflow files nest four levels deep and one list item drifts by a single space.

The quiet failures: valid YAML, wrong data

These all parse without any error. We ran each one; the arrow shows what your program actually receives:

You wroteYAML deliversWhy
country: NOfalseThe Norway problem — YAML 1.1 reads NO/no/Yes/on/off as booleans
answer: yestrueSame boolean coercion
version: 1.101.1Unquoted, so it's a float — trailing zero gone
time: 12:30:4545045Sexagesimal (base-60) notation: 12×3600+30×60+45
zip: 0112344764Leading zero → octal
port: 80 then port: 80808080 onlyDuplicate keys: last silently wins, first is discarded

The fix for the first five is the same: quote any scalar that must stay a string (country: "NO", version: "1.10"). The duplicate-key case is nastier — no quoting saves you, and a merge conflict resolved sloppily can leave two port: lines that both look right. A linter that flags duplicates is the only reliable catch.

Checking YAML before it reaches CI

  • On a Mac, the fastest offline check is Python's parser: python3 -c "import yaml,sys; yaml.safe_load(sys.stdin)" < config.yml — errors print with line and column. yamllint (via Homebrew) adds style checks and duplicate-key detection.
  • On an iPhone or iPad — reviewing a PR from your phone, editing a config over SSH — Yamlite does the same job on-device: paste, and errors appear with line and column instantly, including the duplicate keys and tab indentation cases above. Fully offline, nothing uploaded — which matters when the file you're validating is a production config.
  • In a browser, online validators work but mean pasting your config — often containing secrets and internal hostnames — into someone else's server. For anything sensitive, keep validation local.

FAQ

Why does YAML turn NO into false? YAML 1.1 defines yes/no/on/off/true/false (any case) as booleans. Quote it ("NO") to keep the string. YAML 1.2 dropped this, but most parsers in the wild still speak 1.1.

Are duplicate keys an error in YAML? The spec says keys must be unique, but most parsers accept duplicates and keep the last one silently. Use a linter that flags them — the parser won't.

Why does my YAML fail with a tab error when I can't see any tabs? The tab is invisible. Re-indent the reported line with spaces, or run the file through an editor's convert-tabs command.

What's the fastest way to validate YAML on iPhone? An on-device validator like Yamlite — paste the file, read the line/column errors. No upload involved.

---

Config files travel with the rest of your toolchain — if you're batch-fixing filenames before a deploy, the same care-first instinct applies to batch renaming on Mac.

#yaml#devops#ci#docker-compose#github-actions#debugging

Written by

Peter Zhang

Building local-first Mac & iOS productivity apps at Obelisk Club.