JSON errors, explained
Every page here takes one exact error message and answers three questions: what the parser was actually complaining about, what causes it in real code ranked by how often, and what to change. Each one embeds the validator, so you can fix your payload without leaving the page.
The messages are measured rather than remembered. Every V8 and Python string on this site came from running the parser. Firefox and Safari strings are deliberately absent, because we could not execute and verify them, and publishing a guess about an error message on a site whose whole argument is correctness would be a poor trade.
Or just paste the payload
Nothing you paste leaves your browser. The connect-src allowlist makes that a browser guarantee rather than a promise. Check it yourself
JavaScript, Node and Chrome
Measured on Node v24.15.0 with V8 13.6.233.17. V8 rewrote nearly all of these messages in 2022, so each page carries both the current wording and the one you will find in older answers.
-
Unexpected token '<', "<!DOCTYPE "... is not valid JSONThe server returned an error page , and 4 other causes. -
Unexpected end of JSON inputThe string is empty , and 4 other causes. -
"[object Object]" is not valid JSONThe value was already parsed , and 2 other causes. -
"undefined" is not valid JSONA storage key that was never set , and 2 other causes. -
Unexpected non-whitespace character after JSON at position N (line L column C)The input is NDJSON or JSON Lines , and 3 other causes. -
Bad control character in string literal in JSON at position N (line L column C)Multi-line text pasted directly into a string , and 3 other causes. -
Bad escaped character in JSON at position N (line L column C)A Windows file path with single backslashes , and 3 other causes. -
Expected double-quoted property name in JSON at position N (line L column C)A trailing comma before the closing brace , and 2 other causes. -
Expected property name or '}' in JSON at position N (line L column C)Single-quoted keys, from a Python dict printed with str() , and 3 other causes. -
Expected ',' or '}' after property value in JSON at position N (line L column C)A missing comma between properties , and 3 other causes. -
Unterminated string in JSON at position N (line L column C)An unescaped double quote inside the value , and 3 other causes.
Python
Measured on CPython 3.14.3. Two of these messages are new in Python 3.13, so the version matters and each page says which.
-
Expecting value: line 1 column 1 (char 0)The response body is HTML, not JSON , and 3 other causes. -
Extra data: line L column C (char N)The file is JSON Lines , and 2 other causes. -
Expecting ',' delimiter: line L column C (char N)An unescaped double quote inside a string , and 3 other causes. -
Expecting property name enclosed in double quotes: line L column C (char N)A Python dict printed rather than serialised , and 2 other causes. -
Invalid control character at: line L column C (char N)Multi-line text inside a string , and 2 other causes. -
Invalid \escape: line L column C (char N)A Windows path , and 2 other causes. -
Unterminated string starting at: line L column C (char N)An unescaped quote inside the value , and 2 other causes.
PHP
PHP fails silently by default, which is the real problem. The page covers how to get an actual message out of it.
C# and .NET
Newtonsoft.Json and System.Text.Json word the same failure differently.
Java
Jackson, which is what almost everything in the JVM ecosystem uses underneath.
The four mistakes behind most of these
Strip away the wording and nearly every message on this page comes from one of four things.
- It is not JSON at all
- An HTML error page, an empty body, a plain-text message. The parser is right and the request is wrong. Check the status code and the Content-Type before you check the body.
- It is JavaScript or Python, not JSON
- Single quotes, unquoted keys, trailing commas, True and None. Almost always a dict or an object literal that was printed rather than serialised. Repair fixes all of it.
- A string was built by concatenation
- Which means values were never escaped, so a quote or a newline inside one breaks the document. Serialising instead makes this class of bug impossible.
- It is several documents, not one
- NDJSON read as a single value. Read it line by line or wrap the records in an array.