JSON is small enough that its whole grammar fits on one page, yet "Unexpected token" is one of the most searched error messages in programming. Almost every failure comes from one of ten habits carried over from JavaScript or Python. Here are the rules, then the mistakes.
The rules
- A document is a single value, usually an object or array, but any of the six types is allowed at the top level.
- Object keys are strings in double quotes. Keys and values are separated by a colon, pairs by commas.
- Array items are separated by commas.
- Strings use double quotes only. Inside a string, backslash escapes are
\"\\\/\b\f\n\r\tand\uXXXX. Raw control characters such as a literal tab are not allowed. - Numbers are decimal. Optional minus sign, no plus sign, no leading zeros except a bare zero, optional fraction, optional exponent. No hex, octal, NaN or Infinity.
- The literals are exactly
true,falseandnullin lowercase. - Whitespace between tokens is ignored. Whitespace means space, tab, line feed and carriage return only.
- There are no comments.
The ten errors
1. Trailing comma
{"a": 1, "b": 2,} ✗
{"a": 1, "b": 2} ✓
JavaScript and Python allow a comma after the last item. JSON does not. This is the single most common error.
2. Single quotes
{'name': 'Ada'} ✗
{"name": "Ada"} ✓
Python's print(dict) output looks like JSON but uses single quotes. Use json.dumps instead.
3. Unquoted keys
{name: "Ada"} ✗
{"name": "Ada"} ✓
Valid JavaScript object literal, invalid JSON.
4. Comments
{
// the user name
"name": "Ada"
} ✗
Some tools such as VS Code settings accept comments in files they call JSONC, but a standard parser will reject them. Strip them out or use a JSON5 or JSONC parser.
5. Missing comma between items
{"a": 1 "b": 2} ✗
{"a": 1, "b": 2} ✓
Usually happens when pasting two fragments together. The error is reported at the start of the second key.
6. Unescaped quotes inside a string
{"quote": "She said "hi""} ✗
{"quote": "She said \"hi\""} ✓
7. Raw line breaks inside a string
{"text": "line one
line two"} ✗
{"text": "line one\nline two"} ✓
8. Wrong capitalisation of literals
{"ok": True, "v": NULL} ✗
{"ok": true, "v": null} ✓
Python writes True and None. JSON needs lowercase true and null.
9. Invalid numbers
{"n": 007} ✗ leading zero
{"n": .5} ✗ must be 0.5
{"n": +1} ✗ no plus sign
{"n": NaN} ✗ not a JSON value
{"n": 0x1F} ✗ no hex
10. Undefined, functions and dates
{"cb": function() {}, "when": new Date()} ✗
These are JavaScript values with no JSON form. JSON.stringify silently drops undefined and functions and turns dates into strings, which is why the same object can round trip differently than you expect.
Bonus: duplicate keys
{"a": 1, "a": 2}
This is technically allowed by the grammar but the specification says behaviour is undefined. Nearly every parser keeps the last value. Do not rely on it.
Reading the error message
Browsers and Node report the position where the parser gave up, for example "Unexpected token } in JSON at position 27" or, in newer versions, a line and column. The real mistake is often a few characters earlier, such as a missing comma on the previous line. Paste the text into our JSON validator to get the line and column, then look just before that spot.