A JSON.parse “Unexpected token” error means the parser reached a character that JSON does not allow at that point in the text, so it stopped. The usual culprits are a trailing comma, single quotes, an HTML page where JSON was expected, an empty response, or a byte order mark at the start of a file. PrismKit, a free Windows utility from Automata Labs, includes a JSON formatter and validator that runs offline, so you can paste a payload, see whether it is valid, and pretty print it without sending API data to a website.
The exact wording depends on the engine. This guide lists the messages you are most likely to see in Node.js and Chrome, Firefox and Python, what causes each one, and how to fix it.
Paste the payload into PrismKit’s JSON validator and format it, offline, from a hotkey.
Get it from Microsoft
What does each JSON.parse error message mean?
We ran each broken input through JSON.parse in Node.js 20, which uses the V8 engine also found in Chrome, and through the json module in Python 3.13. Messages change between versions, so treat the wording as a guide rather than an exact match.
| Input | Node.js 20 (V8) message | Python 3.13 message | Cause |
|---|---|---|---|
[1, 2, 3, 4,] | Unexpected token ']', "[1, 2, 3, 4,]" is not valid JSON | Illegal trailing comma before end of array | Trailing comma |
{"foo": 1,} | Expected double-quoted property name in JSON at position 10 | Illegal trailing comma before end of object | Trailing comma in an object |
{'a': 1} | Expected property name or '}' in JSON at position 1 | Expecting property name enclosed in double quotes | Single quotes |
| (empty string) | Unexpected end of JSON input | Expecting value: line 1 column 1 (char 0) | Nothing to parse |
{"a": 1 | Expected ',' or '}' after property value in JSON at position 7 | Expecting ',' delimiter | Truncated text |
<!DOCTYPE html> | Unexpected token '<', "<!DOCTYPE html>" is not valid JSON | Expecting value | An HTML page, not JSON |
undefined | "undefined" is not valid JSON | Expecting value | A missing value was converted to a string |
BOM then {"a":1} | Unexpected token followed by an invisible character | Unexpected UTF-8 BOM (decode using utf-8-sig) | Byte order mark at the start |
{"a":1} x | Unexpected non-whitespace character after JSON at position 8 | Extra data | Something after the JSON value |
{"a": 01} | Unexpected number in JSON at position 7 | Expecting ',' delimiter | Leading zero in a number |
Firefox uses its own wording. MDN’s JSON.parse bad parsing reference lists messages such as JSON.parse: unexpected character, JSON.parse: expected property name or '}', JSON.parse: unexpected end of data and JSON.parse: unterminated string.
What does “position” mean in the error?
In V8 messages, the position is a zero-based character offset into the string you passed. Python reports the same idea as line, column and char. To see what sits at that offset, print the text around it:
const pos = 10; // from the error message
const around = text.slice(Math.max(0, pos - 30), pos + 30);
console.log(JSON.stringify(around));
// Code points of the first few characters, to spot a BOM (feff)
console.log([...text.slice(0, 5)].map(c => c.codePointAt(0).toString(16)));
JSON.stringify shows control characters such as a raw tab as escape sequences. A byte order mark is not escaped, so the second line prints the code points at the start of the text, where a BOM shows up as feff. For a long payload on one line, pretty printing it first makes the problem easier to spot by eye.
What are the rules JSON actually enforces?
The format is defined in RFC 8259. Most of the errors above come from a handful of its rules:
| Rule in RFC 8259 | What breaks it |
|---|---|
| Strings, including object member names, begin and end with quotation marks | Single quotes, or unquoted keys copied from JavaScript |
| Values are separated by commas, with no comma after the last one in the grammar | Trailing commas |
| Numeric values that cannot be represented as digits, such as Infinity and NaN, are not permitted | NaN or Infinity in output from some serializers |
| Implementations must not add a byte order mark to networked JSON; parsers may ignore one | A BOM written by an editor or export tool |
| Control characters inside strings must be escaped | A raw tab or newline pasted into a string value |
Note that Python’s json module accepts NaN and Infinity by default, while JSON.parse rejects them. Data that loads in Python can therefore fail in a browser.
Format and validate JSON, XML, SQL and HTML in one offline command palette. The core tools are free.
Get it from Microsoft
Why do you get Unexpected token '<' from fetch?
This one is rarely a JSON problem. The server sent HTML, usually an error page, login page or a 404 from the wrong URL, and your code called JSON.parse or response.json() on it. Check the status and content type before parsing:
const res = await fetch(url);
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 same pattern explains “Unexpected end of JSON input” on a 204 No Content response or any empty body: there is nothing to parse.
How do you fix the most common causes?
| Cause | Fix at the source | Quick fix for a one-off file |
|---|---|---|
| Trailing comma | Generate JSON with a serializer (JSON.stringify, json.dumps) instead of string building | Delete the last comma before the closing bracket |
| Single quotes | Same as above | Replace with double quotes, escaping any quotes inside values |
| HTML response | Fix the URL, the authentication, or the server error | Read the response as text to see the page |
| Empty response | Handle empty bodies before parsing | Confirm the request actually returned data |
| BOM | Save files as UTF-8 without BOM; in Python, read with utf-8-sig | Strip the first character if it is U+FEFF |
| undefined | Check the variable before parsing; it was never set | Find where the value is lost |
| NaN or Infinity | Replace with null or a string before serializing | Edit the values |
| Extra data | Separate multiple JSON documents, or use a format such as JSON Lines | Parse each line on its own |
How does PrismKit help?
PrismKit is a keyboard-first utility for Windows. You press a hotkey, type the tool you want into the command palette, and paste. For JSON work, the free core tools include:
- JSON formatter and validator, to check whether a payload parses and pretty print it so a stray comma or quote is easy to see.
- Base64 and URL decoding, for JSON that arrives encoded in a query string or a header.
- JWT inspection, to read the JSON header and payload inside a token.
- XML, SQL and HTML formatters, for the other payloads in the same session.
Everything runs offline on your PC, with no tracking or telemetry, so API keys and customer data in a payload never leave the machine. That matters when the broken JSON came from a production log. Our guides to formatting and minifying JSON locally and decoding Base64 and URL encoded JSON go further.
The core tools are free forever. Optional add-on packs, the Enhanced Pack and the Prompt Engineering Pack, are one-time lifetime purchases if you want more.
Frequently asked questions
What does “Unexpected end of JSON input” mean?
The parser reached the end of the text before the JSON was complete. The input was empty or cut off, often because a request returned no body.
Why does JSON.parse fail on single quotes?
JSON strings, including property names, must use double quotes. JavaScript object literals allow single quotes, JSON does not.
Are trailing commas allowed in JSON?
No. JSON’s grammar has no comma after the last element, and both JSON.parse and Python’s json module reject one.
Is it safe to paste JSON into an online validator?
It depends on the data. If the payload includes keys, tokens or personal data, use a tool that runs locally, such as PrismKit, so nothing is uploaded.
Try PrismKit
PrismKit is free in the Microsoft Store, with its core tools free forever and optional one-time add-on packs. More detail is on the PrismKit product page.
Check and format JSON offline from a hotkey, and keep payloads on your own PC.
Get it from Microsoft
Windows is a trademark of the Microsoft group of companies. Chrome is a trademark of Google LLC. Firefox is a trademark of the Mozilla Foundation. Node.js is a trademark of the OpenJS Foundation. PrismKit is not affiliated with these companies.
Last updated 20 October 2026. Published by Automata Labs, a software company in Canada.