"Unexpected token < in JSON at position 0" is one of the most searched error messages in web development. The message looks cryptic, but the character it names and the position it reports almost always point straight at the cause. This guide decodes the common JSON parse errors across browsers, Node.js and Python, and shows how to fix each one.
A parse error tells you two things:
The real mistake is often just before that position. A trailing comma, for instance, is reported at the closing brace that follows it.
Different engines word the same problem differently:
| Engine | Example message |
|---|---|
| Chrome / Node.js | Unexpected token '<', "<!DOCTYPE html>" is not valid JSON |
| Firefox | JSON.parse: unexpected character at line 1 column 1 of the JSON data |
| Safari | JSON Parse error: Unrecognized token '<' |
| Python | json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0) |
The response is HTML, not JSON. You asked for JSON but received a web page, usually one of these:
index.html, because a single-page app's fallback route answered an API URL that doesn't exist.Fix: check response.ok and the Content-Type header before parsing, and log the first part of the body when it isn't JSON:
javascriptconst res = await fetch('/api/orders'); const type = res.headers.get('content-type') || ''; if (!res.ok || !type.includes('application/json')) { const body = await res.text(); throw new Error(`Expected JSON, got ${res.status}: ${body.slice(0, 200)}`); } const data = await res.json();
The input is empty or truncated. Common causes:
204 No Content, or an empty body with status 200.response.json() on a response to a HEAD request.Fix: check for an empty body before parsing, and treat it as "no data" rather than an error if the API allows it.
"undefined" is not valid JSONOlder browsers and Node.js versions use the first wording; current versions use the second. Either way, you're parsing the string "undefined". That usually means JSON.parse(localStorage.getItem('key')) ran when the key had never been set, or a variable was undefined and got converted to a string. Check for a missing value first.
"[object Object]" is not valid JSONYou're parsing something that's already an object. JSON.parse({}) converts the object to the string "[object Object]", which isn't JSON. Older engines report the o at position 1; current ones quote the whole string. Remove the extra JSON.parse, which often follows response.json() or an axios response, since axios parses JSON for you.
These point to a syntax mistake inside otherwise valid JSON:
| Message mentions | Likely cause | Fix |
|---|---|---|
} or ] after a comma | Trailing comma | Remove the last comma |
' (single quote) | Single-quoted strings or keys | Use double quotes |
/ | A comment | Remove // and /* */ comments |
A letter such as N, I or u | NaN, Infinity or undefined | Use null or remove the key |
| A letter at the start of a key | Unquoted key {a: 1} | Quote the key |
Bad control character | A raw line break or tab in a string | Escape it as \n or \t |
Each case is explained with examples in Validate JSON (common errors & fixes).
The input contains more than one JSON value, such as two objects one after another, or a valid object followed by extra text. If each line is a separate record, the data is NDJSON and must be parsed line by line.
Content-Type of the response.For language-specific details, see Parse and stringify JSON in JavaScript and Work with JSON in Python.