“Unexpected token in JSON”: what it means and how to fix it
Your code called JSON.parse or response.json() and got an error that seems to blame a random character. The message is usually telling you something quite specific.
Read the message first
| You see | What it almost always means |
|---|---|
Unexpected token '<', "<!DOCTYPE "... is not valid JSON | The server sent an HTML page: a 404, 500, login redirect or the app's index.html |
Unexpected end of JSON input | Empty body (204 No Content, a failed request) or a cut-off response |
"undefined" is not valid JSON | You passed the JavaScript value undefined, e.g. a missing localStorage key |
Expected double-quoted property name … position 7 | A trailing comma before } or ], or an unquoted key |
Unexpected token ''' / Expected property name | Single quotes instead of double quotes |
Python: Expecting value: line 1 column 1 (char 0) | Empty or non-JSON text, same causes as the first two rows |
Older browsers word it as Unexpected token < in JSON at position 0; the meaning is the same. The position is a character offset from the start, counting from 0.
Position 0: you did not get JSON
This is the most common case and the JSON is not the problem. Log the raw text before parsing it:
const res = await fetch(url);
const text = await res.text();
console.log(res.status, res.headers.get("content-type"), text.slice(0, 200));
const data = JSON.parse(text);
Typical culprits: a wrong URL that falls through to your single-page app's index.html, a dev-server proxy that is not set up, an expired session redirecting to a login page, a server error page, or an API that answers errors in plain text. Check res.ok before parsing, and look at the Network tab in developer tools for the real response.
Further in: the JSON itself is broken
JSON is much stricter than JavaScript. These are all invalid:
{ "a": 1, } // trailing comma
{ 'a': 1 } // single quotes
{ a: 1 } // unquoted key
{ "a": 1 } // note // comments
{ "a": NaN } // NaN, Infinity and undefined are not JSON
{ "path": "C:\new" } // a lone backslash must be written \\
Paste the text into the JSON formatter: it uses the browser's own strict parser and shows the line and column of the first problem, which is easier to read than a raw position in a one-line file. If you are not sure what the text even is, What is this? will tell you whether it is JSON, YAML, HTML, Base64 or something else.
Other sneaky causes
- A byte-order mark (an invisible character) at the start of a file saved by some Windows editors.
- Parsing twice:
response.json()already returns an object; callingJSON.parseon that object turns it into the text "[object Object]" first, which fails. - Several JSON objects in one file, one per line (JSON Lines). Parse each line separately.
- Config files with comments such as tsconfig.json are JSONC, not JSON; a plain parser rejects them. If you want comments and no quotes, YAML may suit better, and the YAML to JSON converter moves between the two.
Does the file contain lines like <<<<<<< HEAD or =======? A git merge left conflict markers behind: see git merge conflict markers.
Empty or cut-off body instead of a bad token? See Unexpected end of JSON input.
Questions
What does Unexpected token < in JSON at position 0 mean?
The first character of the response is <, so you received HTML instead of JSON, usually an error page, a login redirect or your app's index.html. Log the raw response text and status to see which.
How do I find position N in my JSON?
Count characters from 0, or paste it into a JSON formatter that converts the position into a line and column for you.
Can JSON have trailing commas or comments?
No. Standard JSON allows neither. Some tools accept JSON5 or JSONC, which do, but JSON.parse and most APIs do not.
Why does JSON.parse(undefined) fail?
JSON.parse turns its argument into text first, so undefined becomes the word undefined, which is not valid JSON. Check the value exists before parsing.
Published .