The reported position is where the parser gave up, not always where you typed the mistake: a missing comma on line 4 shows up as an unexpected token at the start of line 5. The JSON Formatter & Validator highlights that line in the gutter. Fix the first error, re-validate, and repeat — parsers stop at the first violation.
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 Diff Checker to see exactly what changed when something breaks.