Skip to content

YAML error

“control characters are not allowed”

The file contains a byte that YAML forbids anywhere in a document: a control character such as a terminal escape code, a form feed, a NUL byte or DEL. The usual source is coloured command output redirected into a file. Find the byte with grep and delete it.

By yamltojsonfree · Published · Updated

What the parser is telling you

YAML documents may contain tab, line feed, carriage return and any printable Unicode character. Everything else in the control range is rejected before parsing even starts: bytes 0 to 8, 11, 12, 14 to 31, 127 and the C1 range 128 to 159. That is why some tools report a byte position rather than a line number, and why kubectl reports no position at all.

The characters are invisible in most editors, so the file looks fine. The most common source is an ANSI escape sequence, byte 27, left behind when coloured command output was redirected into a file. Zero-width spaces and non-breaking spaces are printable and do not raise this error, but they silently become part of keys and values, which is its own problem.

Who prints this message

libyaml and go-yaml, so kubectl, Helm, Docker Compose and Ruby print it. PyYAML with the C loader prints “unacceptable character #x001b: control characters are not allowed”; its pure-Python loader says “special characters are not allowed”. js-yaml says “the stream contains non-printable characters”.

The causes, with fixes

Broken YAML on the left, the corrected form on the right. The fix under each pair is the one that applies to that cause.

Terminal colour codes in the file

Redirecting the output of a command that colours its output, such as grep --color=always or a tool with colour forced on, writes escape sequences into the file. Each one starts with byte 27.

Broken

name: api\x1b[0m
image: nginx

Fixed

name: api
image: nginx

Fix: The broken example shows the escape byte as \x1b; in the file it is invisible. Strip them with sed -E 's/\x1b\[[0-9;]*[A-Za-z]//g' file.yaml, or re-run the command with --color=never.

A NUL byte or a binary fragment

A file truncated during a write, or a value pasted from a binary or a hex dump, carries byte 0 or other control bytes.

Broken

name: a\x00pi

Fixed

name: api

Fix: Find the exact position with grep -nP "[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]" file.yaml and delete the byte.

Invisible characters that do not raise this error

A non-breaking space at the start of a line is not whitespace to YAML, so the document below parses without error as a key that begins with two non-breaking spaces. The document is valid and wrong.

Broken

a:
\u00a0\u00a0b: 1

Fixed

a:
  b: 1

Fix: Search for non-breaking spaces with grep -nP "\xa0" file.yaml and zero-width spaces with grep -nP "\x{200b}" file.yaml, then replace them with ordinary spaces or delete them.

Find it fast

  1. 1.Run cat -v file.yaml and look for ^[, ^@ or ^L: those are escape, NUL and form feed.
  2. 2.Run grep -nP "[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]" file.yaml to get the line numbers.
  3. 3.Re-run whatever produced the file without colour, for example with --color=never or NO_COLOR=1.
  4. 4.Paste the document into the YAML validator on this site to confirm it is clean; it rejects a stream that still contains non-printable characters.

The same error in other parsers

ParserMessage
libyaml, go-yaml (kubectl, Helm, Compose), Ruby Psychcontrol characters are not allowed
PyYAML, pure-Python loaderunacceptable character #x001b: special characters are not allowed
js-yaml (Node, most browser tools)the stream contains non-printable characters
yaml (npm)accepts the file and keeps the character

Frequently asked questions

Are emoji and accented characters allowed in YAML?

Yes. Any printable Unicode character is valid in keys and values as long as the file is saved as UTF-8, which is what every parser assumes. The error is only about control characters, not about non-ASCII text.

Do Windows line endings cause this error?

No. Carriage return is one of the three control characters YAML allows, so CRLF files parse. A file with only carriage returns and no line feeds parses too. The formatter on this site converts line endings to LF if you want them normalised.

kubectl reports it without a line number. How do I find the character?

go-yaml rejects the byte while reading the stream, before it counts lines, so the message has no position. Use grep -nP with the control-character class above, which prints the line number, or cat -v, which makes the characters visible.

Related errors

All six underlying mistakes, ordered by cause rather than by message, are in the guide Common YAML errors and how to fix them. Every one of them is caught with the exact line and a suggested fix by the free tools below; nothing is uploaded.