Why Your JSON Is Invalid: The Errors That Cause Almost Every Parse Failure
JSON is a deliberately small format, so the list of things that can break it is short. Nearly every parse failure comes from one of six causes, and most of them are the result of JavaScript object literals being more permissive than the JSON specification.
1. The trailing comma
A comma after the final element of an object or array is legal in modern JavaScript and illegal in JSON. This is the single most frequent cause of parse failures, and it is particularly common in hand-edited configuration files where the last entry was removed but its comma was not.
Error messages usually name the position of the closing brace rather than the comma itself, so look at the line above the one the parser reports.
2. Single quotes
JSON requires double quotes for both keys and string values. Single quotes are valid JavaScript and invalid JSON, and unquoted keys — perfectly normal in an object literal — are equally invalid. Data copied out of a debugger or a console log almost always arrives in the JavaScript form and needs converting before a parser will accept it.
3. Unescaped characters inside strings
A literal newline, tab or unescaped double quote inside a string terminates it early, and the parser then fails somewhere further along with a message that points nowhere useful. Newlines must be written as the two characters backslash-n, tabs as backslash-t, and internal quotes must be escaped.
Backslashes in file paths cause this constantly: a Windows path has to double every backslash. This is also where the error location is least helpful, because the parse breaks at the point the damage becomes syntactically impossible rather than where the bad character sits.
4. Comments
JSON has no comment syntax. Neither double-slash nor slash-star survives a standard parser. JSONC and JSON5 add them and several tools accept them in configuration files, but anything going over the wire to a strict parser must have them removed.
5. Values JSON does not have
JSON supports strings, numbers, booleans, null, objects and arrays. It has no undefined, no NaN, no Infinity, no dates and no comments. Serialising a JavaScript object containing undefined silently drops those keys; serialising NaN produces null. Dates become strings, conventionally ISO 8601, and it is the receiving code's job to parse them back.
Large integers are worth attention too. Numbers beyond roughly 9 quadrillion lose precision when parsed into a double-precision float, which is why APIs return large IDs as strings.
6. Encoding and invisible characters
A byte order mark at the start of a file breaks parsers that do not strip it. Smart quotes substituted by a word processor are not quote characters at all. Non-breaking spaces pasted from a web page look identical to ordinary spaces and are not.
When JSON looks correct and still fails, this category is usually responsible. The quickest test is to paste it into the JSON formatter and validator, which names the character position of the fault — and once it parses, formatting it reveals structural problems that are invisible in a minified blob.
A debugging order that works
Validate first, then transform. Attempting to convert malformed JSON produces output that looks plausible and is subtly wrong, which is far more expensive than a clean failure.
- Paste the raw payload into a validator and fix the first reported error only, then revalidate — one fault frequently produces several downstream messages.
- Format it and read the structure. Nesting that surprises you usually indicates the real bug.
- Compare against a known-good sample with a diff checker when a payload that used to work has stopped.
- Only then convert or import it.
For data arriving from spreadsheets, the boundary is the usual suspect: quoted fields containing commas, inconsistent headers, and locales where the field delimiter is a semicolon because the comma is the decimal separator. The CSV to JSON converter tracks quote state rather than splitting blindly, and the JSON to CSV converter takes the union of keys across the array so fields appearing only in later records are not dropped.
One last note on encoded payloads: if a value arrives as an opaque block of Base64, decode it before assuming it is corrupt. A Base64 decoder will show whether there is valid JSON inside, and a JWT decoder does the same for tokens, whose payload is simply Base64url-encoded JSON.