The most classic error message
SyntaxError: Unexpected token } in JSON at position 5
Every developer's first JSON.parse runs straight into it. The message is actually rich: it tells you which character index (position), which token went wrong, and that this is a syntax-level error, not a value-access problem. This article breaks down the four most common error classes and gives you a workflow you can actually use.
How to read the message
JSON.parse(arg) always throws SyntaxError, but two fields matter:
- position: the zero-based index of the failing char; jump straight there in the string.
- the token in the message: e.g.
},,,o,1—the char actually read at that spot.
Most parsers/validators draw an arrow to the failing point, which is exactly where you start.
Error class one: Unexpected token 'x'
JSON.parse('{"a":1,,}') // Unexpected token ','
JSON.parse("{a:1}") // Unexpected token 'a' —— unquoted key
JSON.parse("{'a':1}") // Unexpected token ' — single quotes
Standard JSON has three hard rules that heavy JavaScript use makes people forget:
- Keys must be double-quoted—no bare names, no single quotes;
- No comments (
//,/* */are illegal); - No trailing commas—see below.
If a backend returns a "JSON-like but JS-style" string, fix it at the source rather than fighting it at parse time.
Error class two: Unexpected end of JSON input
JSON.parse('{"a":1') // Unexpected end of JSON input
JSON.parse('') // same error on empty string
This usually means the string is not complete: either you cut the tail, or a network/storage layer truncated it. Whenever you see "Unexpected end" near the end, suspect payload truncation before blaming a missing bracket.
Error class three: trailing comma
{"a":1,} → Unexpected token '}'
[1,2,] → Unexpected token ']'
JS object/array literals permit trailing commas, so it slips into JSON naturally. Trick: many online JSON formatters auto-append a trailing comma to objects; running that output through a strict validator misreports. Pick a "strip trailing commas" / no-comma option instead.
Error class four: Unexpected token o
const obj = {name:'k'};
JSON.parse(obj) // Unexpected token o in JSON at position 0 ← 'o' of [object Object]
JSON.parse('123') // valid! yields a number, no throw
The argument must be a string (or valid input that coerces to one). Parsing an already-parsed object turns it into [object Object] via toString, hence the o.
A three-step debugging workflow
When you get a soup of JSON, don't eyeball it—do this:
- Format: throw it into a JSON formatter; minified JSON becomes a tree/indented, and wherever the error arrow points becomes obvious. This is the most-skipped yet most effective step.
- Character audit: use find/replace to highlight risky patterns like
,\n,{\n,[\n; check for trailing commas, unquoted keys and leftover comments, and catch any stray HTML/log prefixes smuggled into the payload. - Bisect: for payloads hundreds of KB+ failing near the end, parse the front and back halves separately to narrow the problem, and use the byte offset to check whether a multi-byte character was cut in half.
Why "it looks right" still fails
Three common illusions:
- Editor/browser already converted it: paste auto-converts curly quotes/full-width colons to half-width, so you think it's fine.
- An extra layer of serialization: the backend double-wrapped it, or the frontend stringified a string again—parsing yields a quoted string, not an object.
- Escaping went wrong:
\uXXXXescapes weren't restored, or newlines are literal (inside JSON strings they must be\n).
Self-check
Feed this broken example to a JSON validator/formatter and find three problems:
{
name: "k",
"tags": ["a", "b",],
"note": "line break
here"
}
If you can point out "unquoted key, trailing comma, literal newline in string" and predict each error token, JSON.parse errors stop being a mystery.