Cryonel

"Bad control character in string literal" Error, Explained

JSON string values can't contain a literal newline, tab, or other control character — they have to be escaped. This is a stricter rule than most people expect coming from other languages.

What triggers it

{
  "note": "line one
line two"
}

That raw newline inside the string breaks parsing with something like Bad control character in string literal in JSON at position 11. The same happens with a literal tab character, or with control characters copy-pasted in from another source (e.g. terminal output with embedded control codes).

Why JSON requires this

RFC 8259 requires control characters (U+0000 through U+001F) inside a string to be escaped — a newline must be written as \n, a tab as \t, and so on. This keeps JSON text unambiguous and safe to embed in other formats without a raw byte silently breaking line-based tooling (like log parsers) downstream.

How to fix it

Find the invisible byte

Start with the line and column reported by the parser, then inspect the raw bytes rather than the rendered text. A tab and several spaces can look identical, and a carriage return may be hidden by the editor. In JavaScript, inspect character codes below 32; in a terminal, a hex viewer can reveal 09 (tab), 0a (line feed), 0d (carriage return), or 00 (null).

Decide whether the character is meaningful data. If a newline belongs in the value, serialize it as \n; if it came from a damaged transport or delimiter, remove it before serialization. Do not replace every control character blindly: tabs and line breaks may be required after the JSON is decoded. Preserve one raw failing fixture and test the serializer so the producer cannot reintroduce the invalid byte.

Frequently Asked Questions

Which control characters are invalid?

Raw U+0000 through U+001F characters are invalid inside JSON strings unless escaped.

How should a newline be stored?

Use the escaped \n sequence in serialized JSON; the decoder restores the newline.

Why can valid-looking copied JSON fail?

Invisible tabs, carriage returns, or null bytes may be present even when the editor does not show them.

Related Tools and Guides