LocalFirstTools.com — data tools that never leave your device
No upload — everything runs on your device

How to fix “Unexpected token” in JSON

Last updated

“Unexpected token” means the JSON parser met a character that cannot legally appear at that position — and stopped. The fix is always the same two steps: find the exact position, then recognize which of a handful of classic mistakes put the illegal character there. Paste the document into the JSON Formatter & Validator and it reports the first error with its precise line and column, highlighting the line in the gutter.

Read the error message first

Browser messages look like Unexpected token } in JSON at position 251 — position counts characters from the start, which is useless in a minified single-line document. A validator that translates position into line and column (and shows you the line) turns a hunt into a glance. Note that the parser stops at the first violation: fix it, re-validate, and repeat if needed.

The five mistakes behind almost every case

  • Trailing commas. {"a": 1, "b": 2,} — legal in JavaScript, illegal in JSON. Reported as an unexpected } or ].
  • Single quotes. {'name': 'Ada'} — JSON strings and keys must use double quotes. Reported as an unexpected ' at the first quote.
  • Unquoted keys. {name: "Ada"} — object keys are strings and need quotes, unlike JavaScript object literals.
  • Comments. // config for prod — no comment syntax exists in JSON. The / is the unexpected token.
  • Raw line breaks or control characters inside strings. A pasted value with a real newline in it must be escaped as \n. Copy-pasting from terminals also smuggles in invisible characters — smart quotes from chat apps are a classic.

Invisible characters: the BOM and its friends

Sometimes the input looks perfect and still fails at position 0 with a baffling Unexpected token in JSON at position 0 — note the seemingly empty quotes. The culprit is usually a byte order mark: Windows editors and PowerShell's Out-File like to prepend U+FEFF to UTF-8 files, and RFC 8259 forbids it at the start of a JSON text. The same family of bugs comes from non-breaking spaces (U+00A0) pasted from web pages and “smart quotes” (“ ”) substituted by chat apps and word processors — visually near-identical to legal characters, lexically illegal. Fix: re-save as “UTF-8 without BOM”, or strip the first character in code with text.replace(/^\uFEFF/, ""); for smart quotes, retype the quotes in a code editor. A validator that points at position 0 or at a quote that looks fine is practically shouting “invisible character”.

Values JavaScript allows but JSON doesn't

NaN, Infinity and undefined are legal JavaScript values with no JSON representation — RFC 8259 numbers are finite, and there is no undefined. Hand-built strings containing them fail with Unexpected token N (from NaN) or Unexpected token I. Note the asymmetry: JSON.stringify(NaN) quietly emits null rather than throwing, so these tokens in a document almost always mean someone concatenated strings instead of serializing. The same goes for 0x1F hex literals and numbers like .5 or +1 — JSON requires 0.5 and 1.

When the JSON is not the problem

Unexpected token < in JSON at position 0 deserves its own mention: the < is the first character of <html>. Your code parsed an HTML error page, a 404, or a login redirect as if it were an API response. The JSON was never malformed — there was no JSON. Log response.text() before parsing, and check the status code and content-type first.

A worked example

{
  "name": "deploy",
  "retries": 3,
  "env": "prod",
}

A validator reports something like Unexpected token } at line 5, column 1. The real mistake is the comma at the end of line 4 — the parser only discovered it when the closing brace arrived where a new key was required. Delete the comma and the document is valid. This one-line-off pattern is why the rule of thumb is: look at the reported position, then one token back.

Prevent it next time

Generate JSON with a serializer (JSON.stringify, json.dumps) instead of string concatenation or hand-editing; serializers cannot produce syntax errors. When hand-editing is unavoidable — config files, fixtures — validate before committing, and diff edited configs with the Text Diff tool to see exactly what changed when something breaks.

Do it now — locally

Pretty-print, minify and validate JSON in your browser. Nothing is uploaded.

Open the JSON Formatter

Frequently asked questions

Why does the error say “Unexpected token < in JSON at position 0”?

Your code called JSON.parse on an HTML page — usually an error page or a login redirect returned where the API response should be. Log the raw response text; the JSON itself is probably fine and the bug is in the request or the server.

Why is the reported line different from where my mistake is?

Parsers report where they gave up, which is at or just after the mistake. A missing comma at the end of line 4 surfaces as an unexpected token at the start of line 5. Look at the reported position and one token backwards.

Are comments really not allowed in JSON?

Correct — RFC 8259 has no comment syntax. Files with // or /* */ are JSONC or JSON5, supersets that need their own parsers (VS Code's settings.json is JSONC, for example). Strip comments before feeding standard parsers.

Is a trailing comma ever valid?

Never in JSON. [1, 2, 3,] and {"a": 1,} are both invalid, even though modern JavaScript allows both in source code. This is the single most common JSON error.

Why does the same text work as a JavaScript object but fail JSON.parse?

JavaScript object literal syntax is a superset: unquoted keys, single quotes, trailing commas, comments, NaN and undefined are all fine in source code but illegal in JSON. Code that eval'd or copy-pasted a literal will not round-trip through JSON.parse unchanged.

Are duplicate keys an error?

Not a syntax error — {"a": 1, "a": 2} parses everywhere. RFC 8259 only says names "should" be unique; JavaScript keeps the last value, other parsers vary, and some security tooling flags duplicates precisely because two systems can read different values from the same document.