What the error means
JSON.parse reads the text one character at a time. When the next character cannot continue a valid document, it throws a SyntaxError that names that character and its position, counted in characters from the start of the text with the first character at 0. For the text {"a" 1}, for example, the unexpected token is the 1, at position 5.
Newer JavaScript engines word it differently and often add the line and column, for example "Expected ',' or '}' after property value in JSON at position 25 (line 3 column 4)", or "Unexpected token '<', "<!DOCTYPE "... is not valid JSON". Safari and Firefox use their own wording. The cause is the same in all of them. The examples below are organised by the character or phrase you see, because that usually identifies the cause.
To locate the spot, paste your text in the editor above and click Validate. The validator reports the line and column, which is easier to find than a character count in a long single-line response.
The usual causes
Start with the token the error names and match it to a case below.
Unexpected token < at position 0
Error: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
Invalid
<!DOCTYPE html> <html>…</html>
Fixed
{"status": "ok"}The text is an HTML page, typically a 404 or 500 error page returned instead of JSON. Check the response status and the URL before calling response.json(), and look at the raw body in the Network tab.
Unexpected token o at position 1
Error: "[object Object]" is not valid JSON (older engines: Unexpected token o in JSON at position 1)
Invalid
JSON.parse({ a: 1 }) // parses the string "[object Object]"Fixed
const data = { a: 1 } // already an object; no parse neededJSON.parse was given an object, so JavaScript converted it to the text "[object Object]" first, and the parser rejected it (older engines stopped at the o, position 1). Only parse strings. Many libraries (axios, fetch's .json()) have already parsed the body.
"undefined" is not valid JSON
Error: "undefined" is not valid JSON
Invalid
JSON.parse(localStorage.getItem('settings')) // key missing: null or undefinedFixed
const raw = localStorage.getItem('settings')
const settings = raw ? JSON.parse(raw) : {}The value was undefined (or the word "undefined" was stored). Guard against a missing value before parsing.
Unexpected end of JSON input
Error: Unexpected end of JSON input
Invalid
{"items": [1, 2, 3Fixed
{"items": [1, 2, 3]}The text stops before the document is complete: an empty response, a truncated download, or a missing closing bracket or brace. An empty string gives exactly this message; a truncated document may instead get "Expected ',' or ']' after array element" in newer engines. Check that the body is not empty and that the whole payload arrived.
Single quotes, unquoted keys, trailing commas
Error: Unexpected token "'"
Invalid
{ 'a': 1, b: 2, }Fixed
{ "a": 1, "b": 2 }These are valid JavaScript object literals but not JSON. Use double quotes on every key and string and remove the trailing comma. The JSON validator guide lists each case.
Invisible characters at the start
Invalid
[BOM]{"a": 1} // an invisible byte order mark (BOM) in front of the braceFixed
{"a": 1}A BOM or other invisible character from a file or copy-paste sits before the first brace. Strip it with text.replace(/^\uFEFF/, ""), or re-save the file as UTF-8 without BOM. Curly “smart quotes” pasted from a document cause the same error.