JSON parsers fail with unhelpful messages at exact positions. This field guide maps the errors you will actually meet — trailing commas, single quotes, unquoted keys, comments, encoding traps — to their causes and fixes, and shows how to hunt an error down when the message will not tell you plainly.
"Unexpected token" is a parser's way of saying: everything was fine until here, and here is where it stopped making sense. That position information — a line and column, if your tool reports them — is the most valuable clue you get, because JSON errors are nearly always local: a missing comma above, a stray character at the caret, a quote that never closed three screens earlier. The format itself is tiny — objects, arrays, strings, numbers, booleans and null — so its failure modes are few and learnable.
What follows is a rogues' gallery: the errors that account for nearly every broken JSON file in the wild, how to recognise each from its symptom, and the fastest route to a file that parses.
Key takeaways
- Read the position first: the reported line/column is where the parser gave up, and the real mistake is usually at or just before it.
- The big five: trailing commas, single quotes, unquoted keys, comments, and strings with unescaped characters.
- JSON is not JavaScript: no comments, no trailing commas, no single-quoted strings, no undefined or NaN.
- Format first, fix second — a pretty-printed file turns a needle-in-haystack search into a glance.
The usual suspects, one by one
| Symptom in the file | Why it breaks | Fix |
|---|---|---|
{"a": 1,} — comma before a closing brace/bracket | JSON forbids trailing commas (JavaScript allows them) | Delete the trailing comma |
{'a': 1} — single-quoted strings | JSON strings must use double quotes | Replace with double quotes — carefully, apostrophes inside text need escaping |
{a: 1} — bare key | Keys must be quoted strings | Quote every key |
// note or /* note */ in the file | JSON has no comment syntax | Remove comments; keep notes in a separate field or file (or switch the pipeline to JSON5/JSONC knowingly) |
"price": 1,299.00 | Commas are separators; numbers cannot contain grouping commas | Write 1299.00 — or make it a string if it is really a label |
"note": "said "hi"" | Unescaped quote ends the string early | Escape as \" — or reword |
"active": True / undefined / NaN | Python/JavaScript literals are not JSON literals | Use true / false / null; NaN and Infinity have no JSON form — use null or a string by agreement |
A worked hunt: the error three lines above the report
Consider a parser complaining at line 14, column 3, in this fragment:
{
"name": "Harbour Lights",
"rooms": 12,
"facilities": ["pool", "sauna"
"breakfast": true
}
Line 13 closes the facilities array's last string but never closes the array and never adds a comma — then line 14 opens a new key while the parser is still inside the array, and the parser quite correctly gives up at the unexpected string. The lesson generalises: when the caret points at something that looks innocent, look at what precedes it — the previous line's ending is the prime suspect. Missing commas and unclosed brackets together account for the majority of real-world JSON breakage, and both hide one line above the reported position.
Encoding and copy-paste traps
Some broken JSON is invisible. Files saved in UTF-16, or carrying a UTF-8 byte-order mark, can fail strict parsers before the first visible character — the fix is to save as UTF-8 without BOM. Text pasted from word processors and web pages may contain smart quotes (“ ”) instead of straight ones, non-breaking spaces, or an ellipsis character where three dots were meant to be; none of these are JSON syntax, however identical they look. And numbers have their own quiet rules: no leading plus, no leading zeros (007 is invalid), and large integers beyond 253 lose precision in many consumers even when they parse — quote them as strings if downstream is JavaScript and the value is an identifier, not a quantity.
A repair workflow that converges
- Run a real parser and note the position. Guessing wastes the one precise clue the parser gives you for free.
- Jump to the position; inspect the character there and the end of the previous line. Fix the first error only.
- Re-run. Parsers report one error at a time; a file with four problems needs four passes. This is normal, not a sign you made it worse.
- Once it parses, format it and skim the structure: indentation makes a misplaced brace — valid JSON, wrong data — visible at last.
- Validate against expectations: the keys, types and counts your consumer needs. "Valid JSON" and "the JSON you meant" are different achievements.
Mistakes and pitfalls
Fixing the line the parser named, repeatedly
The reported position is where understanding failed, which is frequently one token after the true defect. Editing the innocent line rearranges the error message without removing the cause.
Hand-repairing a huge generated file
If a program generates broken JSON, the bug is in the generator — an unescaped string is the classic — and hand-fixes evaporate on the next export. Repair the file to unblock yourself, then fix the producer and regenerate.
Accepting JSON from a system that emits 'JSON-like' text
Feeds that include comments, unquoted keys or single quotes are speaking a dialect (JSON5, JSONC, or a vendor's invention). Convert deliberately with a tool that understands the dialect rather than letting errors surface randomly downstream.
Common questions
Why does JSON forbid trailing commas if JavaScript allows them?
JSON was specified as a minimal, strict interchange subset so parsers in every language could be small and behave identically. Strictness is the feature: a file that parses in Python parses in Go, character for character. Later formats (JSON5, JSONC) relax the rules for human-edited files at the cost of that universality.
My JSON parses but the app still rejects it. Now what?
Then the problem is schema, not syntax: a missing key, a string where a number was promised, an array where an object was expected. Compare against the consumer's documentation or a known-good example, field by field — formatters show syntax; only the contract shows meaning.
How do I include a comment for my future self?
Within pure JSON, you cannot. Conventions: a top-level "_comment" key (harmless if consumers ignore unknown keys), documentation in a sibling README, or a preprocessing step that strips comments from a JSONC source. Choose based on who else parses the file.
To wrap up
JSON errors feel cryptic only until you learn that the format has perhaps eight ways to break and the parser always tells you where it stopped. Position first, previous line second, one fix per pass — and the haystack shrinks to a handful of straws every time.
Try it yourself
The JSON formatter validates as it formats and names the line and column when something is wrong — then beautifies, minifies or sorts keys once the file parses cleanly.