You call JSON.parse() and get SyntaxError: Unexpected token .... The message looks vague, but the cause is almost always one of a handful of mistakes. Here are the seven I see most, with a fix for each.
1. A trailing comma
{ "name": "Ana", "age": 30, }
JSON does not allow a comma after the last item. Remove it: { "name": "Ana", "age": 30 }.
2. Single quotes instead of double quotes
{ 'name': 'Ana' }
This is valid JavaScript, but JSON requires double quotes for both keys and strings.
3. Unquoted keys
{ name: "Ana" }
Every key must be a double-quoted string: { "name": "Ana" }.
4. Comments
JSON has no comment syntax. Both // note and /* note */ cause an error, so strip them before parsing.
5. undefined, NaN or Infinity
These are JavaScript values, not JSON values. Use null, or leave the key out. JSON.stringify already drops undefined for you, but hand-written JSON often contains it.
6. You are parsing HTML, not JSON
If you see Unexpected token '<' (or '<' is not valid JSON), the response probably starts with <!DOCTYPE html>. A 404 or 500 error page came back instead of your API data. Check the status code first, then the content type, and log the start of the body if parsing fails:
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const type = res.headers.get("content-type") || "";
if (!type.includes("application/json")) {
throw new Error(`Expected JSON but got ${type}`);
}
const text = await res.text();
try {
const data = JSON.parse(text);
} catch (err) {
console.error("Invalid JSON, first 200 chars:", text.slice(0, 200));
throw err;
}
Some proxies and CDNs return a 200 status with an HTML login or error page, so checking res.ok alone is not enough.
7. Empty or cut-off input
Unexpected end of JSON input means the text ended too early: an empty string, a truncated download, or a missing closing } or ]. Log the raw text before parsing and check that its length and ending look right.
Find the exact spot
Modern engines tell you the position, e.g. at position 42 or line 3 column 5. Paste your JSON into a formatter to jump straight there. I use the free JSON formatter on Parsekit, which runs entirely in your browser, so nothing is uploaded. For a longer list of error messages and their meanings, see the JSON parse errors guide.
Repair instead of editing by hand
If the JSON came from somewhere messy (a log, a chat tool, a copy-paste), a JSON repair tool can fix trailing commas, quotes and similar issues automatically. Always check the result before you rely on it.
Quick checklist
- Check the Content-Type header before parsing
- Double quotes everywhere
- No trailing commas
- No comments
- Only
true,false,null, numbers, strings, arrays, objects - Check
res.okbefore calling.json()
Which one bites you most often? Tell me in the comments.
Top comments (2)
Number 6 is the one that bites me most. One extra check beyond res.ok: some proxies and CDNs return a 200 with an HTML login or error page, so checking the Content-Type header before calling .json() catches those too. Another habit that helps is reading res.text() first and wrapping JSON.parse in a try/catch, so a failure can log the first 200 characters of the body. That usually shows the problem straight away.
Thanks Jessica, great point. I only covered checking res.ok, but a 200 with an HTML login or error page from a proxy or CDN is exactly the case that gets missed. I’ll add the Content-Type check and the res.text() + try/catch pattern to section 6.