JSON has no version number, no dialects and a grammar that fits on a single page. That strictness is the point — it is why the same document parses identically in every language. It is also why so much text that looks like JSON is not.
Nearly every failure comes from assuming JSON is JavaScript. It is not. It borrowed the syntax and then removed most of it.
The tool JSON Formatter Open it →1. A trailing comma
The most common cause by a wide margin, and the easiest to miss because JavaScript, Python and most modern languages allow it.
Invalid: {"a": 1, "b": 2,} — the comma after the final value has nothing following it.
Arrays have the same rule: [1, 2, 3,] is invalid. Browsers report this as an unexpected token or an unexpected end of input, and the character offset points at the closing brace rather than the comma itself, which sends people looking in the wrong place.
It usually appears after editing — you delete the last entry from a list and leave the comma that separated it from the one before.
2. Comments
JSON has no comment syntax. Neither // like this nor /* like this */ is legal, and this surprises people constantly because config files are exactly where you most want to explain yourself.
Douglas Crockford, who specified the format, removed comments deliberately — they were being used to carry parsing directives, which defeated the goal of a format that means the same thing everywhere.
If you need annotation, the conventional workaround is a comment key the consumer ignores:
{"_comment": "timeout is in seconds", "timeout": 30}
Some tools accept JSON with Comments (JSONC) or JSON5, which permit comments and trailing commas. Those are separate formats. A file that relies on them will not parse as JSON, and you should not hand one to something expecting the real thing.
3. Single quotes, or no quotes
JSON strings use double quotes, and so do keys. All of these are invalid:
{'name': 'value'}— single quotes on both{name: "value"}— unquoted key, legal in JavaScript, not here{"name": 'value'}— mixed
This one turns up most often when someone copies an object literal out of JavaScript source and expects it to work as data. It looks correct because in its original context it was.
4. Smart quotes from a word processor
The nastiest of the six, because the document looks perfect. Paste JSON through Word, Google Docs, Outlook, Slack or many note apps and autocorrect converts straight quotes into typographic ones: " and " instead of ".
They are different Unicode characters — U+201C and U+201D rather than U+0022 — and a parser sees an unquoted string starting with an unexpected symbol. Because the two glyphs are nearly identical at normal font sizes, people stare at the line for a long time.
The related version is a non-breaking space (U+00A0) picked up from a web page, which looks exactly like a space and is not one.
If the JSON came from anywhere other than a code editor and the error makes no sense, suspect invisible characters. Retyping the offending line by hand fixes it faster than inspecting it.
5. Values JavaScript allows and JSON does not
Several things you can write in JavaScript have no JSON equivalent:
undefined— not a JSON value. Usenull.NaNandInfinity— not valid numbers in JSON, despite being valid IEEE 754 floats. Serialisers usually emitnullinstead, silently.- Leading zeros and leading plus signs:
007and+5are invalid. So is a bare decimal point, as in.5or5.. - Hexadecimal literals such as
0xFF. - Dates. There is no date type — dates are strings by convention, usually ISO 8601, and every parser treats them as text unless you convert them yourself.
- Trailing or leading whitespace inside an unquoted number, and single-line strings broken across two lines. A literal newline inside a string must be escaped as
\n.
6. It was never JSON to begin with
Sometimes the parse fails because the response was an HTML error page, a stack trace, or an empty string. An API that returns <!DOCTYPE html> when it hits a 500 produces a parse error mentioning an unexpected token at position 0 — which means the very first character was wrong, and that is your clue.
If the offset in the error is 0 or 1, stop looking for syntax problems and look at what you actually received.
Reading the error message
Error text differs by engine, which makes searching for it frustrating. The same trailing comma produces:
- Chrome and Node: an unexpected token, with a character position and often a line and column
- Firefox: a message naming the expected element, with a line and column
- Python: a description ending in the line and column numbers
Only the position is reliably present, and it points to where the parser gave up — which is generally just after the real mistake, not on it. A missing comma between two entries is reported at the start of the second entry.
Things that parse but still cause trouble
Valid JSON is not always sensible JSON.
- Duplicate keys.
{"a": 1, "a": 2}is technically legal and every parser resolves it differently — most keep the last. If two systems disagree about which wins, you have a bug nobody can see. - Large integers. JavaScript numbers are IEEE 754 doubles, exact only up to 2⁵³−1. A 64-bit database ID beyond that silently loses precision on the way through. Send such IDs as strings.
- Byte order marks. A UTF-8 BOM at the start of a file is invisible in most editors and will break strict parsers. Files saved from Windows tools are the usual source.
A quick checklist
- Check the last item of every object and array for a stray comma.
- Search for
//and/*. - Confirm every quote is a straight double quote, including around keys.
- If the error position is at or near 0, look at what you received rather than its syntax.
- Retype the reported line by hand to rule out invisible characters.