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: nginxFixed
name: api
image: nginxFix: 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\x00piFixed
name: apiFix: 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: 1Fixed
a:
b: 1Fix: 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.Run
cat -v file.yamland look for^[,^@or^L: those are escape, NUL and form feed. - 2.Run
grep -nP "[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]" file.yamlto get the line numbers. - 3.Re-run whatever produced the file without colour, for example with
--color=neverorNO_COLOR=1. - 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
| Parser | Message |
|---|---|
| libyaml, go-yaml (kubectl, Helm, Compose), Ruby Psych | control characters are not allowed |
| PyYAML, pure-Python loader | unacceptable 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
“found character that cannot start any token”
The scanner reached the start of a new token and found a character no YAML token may begin with. In almost every case it is a tab used for indentation. The other two are a value beginning with @ or a backtick, which YAML reserves.
Read the fix“did not find expected key”
The parser was inside a mapping and expected either another key at the same indentation or the end of the block, but found something that cannot be a key: a line dedented by the wrong amount, a list dash, or an invisible character. Line up the indentation of the line it reports with its siblings.
Read the fix“error converting YAML to JSON”
kubectl does not parse YAML directly. It converts each document to JSON first, and this wrapper means that conversion failed because the YAML is malformed. The real error is the part after “yaml: line N:”, and N counts from the start of that document, not from the top of the file.
Read the fixAll 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.
YAML to JSON
Convert YAML into formatted or minified JSON, with errors pinned to the exact line.
OpenJSON to YAML
Turn JSON back into readable YAML, with control over indentation and key order.
OpenYAML Validator
Check YAML for syntax errors and get a plain-English explanation of what went wrong.
OpenYAML Formatter
Reformat messy YAML with consistent indentation and keep your comments intact.
Open