← Back to Blog

Why JSON.parse Throws: The Most Common Errors and How to Hunt Them Down

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:

  1. Keys must be double-quoted—no bare names, no single quotes;
  2. No comments (//, /* */ are illegal);
  3. 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:

  1. 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.
  2. 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.
  3. 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: \uXXXX escapes 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.

Frequently Asked Questions

What does 'Unexpected token o' from JSON.parse mean?

It almost always means you parsed an object that was already an object: `JSON.parse(object)` calls toString() yielding `[object Object]`, and `o` is its first letter. In other words you did not pass a string at all (an actual wrongly-typed string throws 'Unexpected token "x"' where x is the offending char). Fix: confirm the argument is really a string and parse only once—double serialization creeps in easily at storage/transfer boundaries.

Why does copying JSON into a parser report 'trailing comma'?

Standard JSON disallows trailing commas: both `{"a":1,}` and `[1,2,]` throw 'Unexpected token } or ]'. JavaScript object/array literals allow them, so people used to writing JS naturally produce illegal JSON. Some online JSON formatters also append a trailing comma, causing the 'my JSON looks fine but won't parse' illusion. Fix: run a formatter with a 'strip trailing commas' option, or delete the last comma and re-validate.

The JSON from the server keeps failing in the latter half, what do I do?

Suspect **truncation** first: a proxy/gateway cut the body, gzip decompression failed, or the endpoint returned a timeout artifact. To tell: save the raw body and run a 'JSON validator' to see where the error points—if it always fails near the end rather than near your own field, or reports 'Unexpected end of JSON input', truncation/untermination is the likely culprit. Fix: check server logs and the Content-Length/Content-Encoding headers for completeness; during dev, print and compare response.text().length against the declared length.

The string has Chinese/emoji, why does it throw 'Unexpected end'?

It is usually a byte/encoding issue, not the content itself: ①reading with the wrong charset (e.g. declaring utf-8 on latin-1 bytes) drops bits from some sequences; ②a payload truncated right in the middle of a multi-byte char yields a broken sequence after decoding. Standard JSON is UTF-8 and Chinese/emoji may appear raw (unescaped) inside strings, so their presence alone is nothing to fix. Instead: confirm the response is received fully as UTF-8, use a JSON validator to find the exact byte offset, and look backward to see which multi-byte character was cut.

← Back to Blog