What the error means
Two unrelated things produce "Unexpected token" errors that are hard to see. JavaScript values that JSON cannot represent, such as NaN and Infinity, and an invisible byte-order mark (BOM) at the very start of a file.
The message looks like this in Chrome, Edge and Node.js (Firefox and Safari use different wording for the same problems):
Unexpected token 'N', "{"a": NaN}" is not valid JSON
Unexpected token '', "{}" is not valid JSON (the quoted first character is an invisible U+FEFF)Common causes
NaN, Infinity or undefined as values
JSON has only numbers, strings, booleans, null, arrays and objects. NaN and Infinity are not numbers in JSON, and undefined does not exist. Python's json.dumps writes NaN by default, which is a common source of invalid files.
Broken: {"score": NaN, "ratio": Infinity}
Valid: {"score": null, "ratio": null}A byte-order mark at the start of the file
Some Windows editors save UTF-8 files with a BOM, the invisible character U+FEFF. It is not whitespace for JSON, so parsing fails on the first character even though the file looks fine. Save as UTF-8 without BOM, or strip it before parsing.
Other invisible characters
Non-breaking spaces and zero-width characters copied from web pages or documents look like spaces but are not valid between JSON tokens.
How to find the problem
- Paste the text that you passed to JSON.parse into the editor above. The status bar shows the line and column of the first problem, and Go to error jumps there.
- Remember that the position in the message is where the parser gave up, which is often one token after the real mistake. Look at the character before it as well.
- If the text came from a request, log the raw response text before parsing it. In the browser, open the Network tab, select the request and read the Response tab.
Strip a BOM and forbid NaN when exporting
// JavaScript: strip a BOM before parsing
const data = JSON.parse(text.replace(/^\uFEFF/, ""));
# Python: read a BOM file, and refuse NaN when writing
data = json.load(open("data.json", encoding="utf-8-sig"))
json.dumps(data, allow_nan=False)Frequently asked questions
How can I see an invisible character?
Check the length of the text or its first character code, for example text.charCodeAt(0) is 65279 for a BOM. Many editors can also show invisible characters.
What should NaN become?
Usually null, which means "no value". Decide this in your data pipeline instead of letting NaN reach the JSON.