Unexpected token in JSON at position N

The parser reached a character that cannot legally appear where it appeared. The position is where the parser gave up, which is usually just after the real mistake — a comma, a quote or a brace a few characters earlier.

How the message appears

The same fault, worded by different engines. V8 (Chrome, Node, Edge) changed its format around Chrome 109, so older and newer runtimes disagree about the same document.

  • SyntaxError: Unexpected token '}', ..."a": 1,}"... is not valid JSON
  • SyntaxError: Unexpected token } in JSON at position 8
  • SyntaxError: JSON.parse: unexpected character at line 1 column 9 of the JSON data

What causes it

You parsed something that was never JSON

The classic is Unexpected token o in JSON at position 1: position 0 is [, position 1 is o, and the string being parsed is [object Object]. Something called String(value) on an object before JSON.parse saw it. The other common version is Unexpected token <, which means you parsed an HTML page — nearly always a 404 or 500 error page returned where the API was expected to return JSON.

A stray or missing comma

A comma after the last member of an object or array, or a missing comma between two members. JavaScript object literals tolerate the first and JSON does not, which is why code that round-trips through an editor often breaks here.

The wrong kind of quote

Single quotes, smart quotes pasted from a document or chat client (‘ ’ “ ”), or backticks. JSON strings must use plain double quotes.

Double-encoded JSON

A value that is itself a JSON string, so the document contains "{\"a\":1}" rather than {"a":1}. One JSON.parse gives you back a string, not an object, and parsing the result of JSON.stringify twice fails in the other direction.

The fix

Delete the comma after the last array element and the comma after the last object member. JSON allows a comma only *between* two values.

Fails to parse
{
  "name": "Ada",
  "roles": ["admin", "editor",],
}
Parses
{
  "name": "Ada",
  "roles": ["admin", "editor"]
}

The example travels in the URL fragment, which browsers never send to a server.

Worth knowing

  • The reported position counts UTF-16 code units from the start of the string, not lines. Paste the document into the validator above and it converts that offset into a line and column for you.
  • If the position is 0 and the document looks fine, check for a byte order mark — see the BOM page.

No cookies, no accounts, no tracking. Your JSON and text are processed entirely in your browser and never sent anywhere. We count anonymous page views (the page address only, nothing about you or your device), and use localStorage to remember your theme.