Fix Unexpected Token JSON Errors
Published July 16, 2026By Samson PG
Quick answer
“Unexpected token” usually means the parser hit something that is not valid JSON — a comma, a quote, or an HTML login page pretending to be data.
SyntaxError: Unexpected token ... in JSON (or similar) means JSON.parse (or your language’s decoder) hit a character that valid JSON does not allow at that position. The message names a symptom; the fix is to find the bad byte and the producer that emitted it.
Usual culprits
| Symptom / token | Likely cause |
|---|---|
Unexpected token , |
Trailing comma after last property/element |
Unexpected token ' |
Single-quoted strings (JSON needs double quotes) |
Unexpected token < |
HTML error/login page returned instead of JSON |
Unexpected token u (undefined) |
Parsing undefined / empty body as JSON |
| BOM / weird first char | File saved with UTF-8 BOM or concatenated junk |
Comments (//, /* */) and bare NaN/Infinity are also invalid in strict JSON.
Debug steps that work
- Do not guess — paste the raw body into a formatter/validator and jump to the reported position.
- Confirm you are parsing the response body, not a JS object you already have.
- If the first non-space character is
<, you got HTML — check status code, auth, and CDN error pages. - Strip a leading BOM if a file editor added one.
- After it validates, pretty-print for humans or minify for transport — both need valid input first.
Minimal examples
Invalid (trailing comma):
{ "ok": true, }
Valid:
{ "ok": true }
Invalid (single quotes):
{ 'ok': true }
Decoding the error message itself
The character the parser names is the fastest clue you have — it usually identifies the failure without reading the payload:
| Message | What it almost always means |
|---|---|
Unexpected token < in JSON at position 0 |
You got HTML, not JSON — an error page, a login redirect, or a 404 body |
Unexpected token o in JSON at position 1 |
You passed an object to JSON.parse() — it was stringified to [object Object] first |
Unexpected end of JSON input |
The body was empty or truncated — a 204, a dropped connection, or an already-consumed stream |
Unexpected token } / ] |
A trailing comma before the closing bracket |
Unexpected token ' |
Single quotes — valid JavaScript, invalid JSON |
Unexpected non-whitespace character after JSON |
Two documents concatenated, or NDJSON parsed as one object |
“Position 0” is the one worth memorising: it means the very first byte was already wrong, so this is virtually never a syntax slip inside your data — it is the wrong content entirely.
Why HTML shows up where JSON should be
Unexpected token < is the most common of all of these, and it is rarely a JSON problem:
- The request hit a 404 or 500 and the server returned its HTML error page with a normal
Content-Type: text/html. - An auth redirect sent you to a login page instead of the API.
- A proxy, captive portal, or WAF interposed a challenge page.
- The URL was subtly wrong — a missing
/apiprefix, or a relative path resolving against the wrong base.
The fix is not to parse harder. Check response.ok and the content-type header before calling .json(), so a failed request surfaces as a clear HTTP error instead of a confusing parse error several frames away from the real cause.
Things that are valid JavaScript but invalid JSON
JSON is stricter than a JS object literal, which is why hand-written payloads fail so often:
- Comments (
//or/* */) are not allowed. - Trailing commas are not allowed.
- Keys must be double-quoted —
{name: "x"}is invalid. - Strings must use double quotes, never single.
NaN,Infinity, andundefinedare not JSON values.- A leading byte-order mark (BOM) from a text editor breaks parsing at position 0.
Use TryDevSnip JSON Formatter
TryDevSnip JSON Formatter pretty-prints, minifies, and validates in your browser so you can locate the bad token quickly. Handy mid-debug when the payload might include secrets — see also format JSON without pasting to the cloud.
FAQ
Is the line number in the error always right?
It is usually close. Minified one-line JSON reports a huge column — pretty-print first, then re-parse.
Why does it work in the console but fail in my app?
Different strings: escaped quotes, truncated logs, or middleware that wraps the body.
Can minify cause Unexpected token?
Minify of valid JSON stays valid. Minifying invalid input just fails earlier at parse time.
What about JSON5 / JSONC?
Those allow comments and other extensions. Strict JSON.parse will still throw — convert or use a matching parser.