Common JSON Errors and How to Fix Them
· 5 min read
Most invalid JSON comes from a handful of mistakes: a trailing comma, single quotes instead of double quotes, unquoted keys, comments, or a value JSON does not support such as NaN or undefined. Paste the text into a JSON validator to get the exact line and column, then apply the matching fix below.
JSON's grammar (RFC 8259) is deliberately small. That is why it is easy to break: anything you are used to from JavaScript object literals, Python dicts or YAML that is not in the spec is an error.
Quick reference
| Mistake | Invalid | Valid |
|---|---|---|
| Trailing comma | [1, 2, 3,] | [1, 2, 3] |
| Single quotes | {'a': 'b'} | {"a": "b"} |
| Unquoted key | {a: 1} | {"a": 1} |
| Comment | {"a": 1 // note} | {"a": 1} |
| Missing comma | {"a": 1 "b": 2} | {"a": 1, "b": 2} |
| Unsupported value | {"a": NaN} | {"a": null} |
| Python literals | {"a": True, "b": None} | {"a": true, "b": null} |
| Leading zero | {"zip": 02134} | {"zip": "02134"} |
| Hex number | {"color": 0xff} | {"color": 255} |
What the error messages mean
Parsers report the position where they gave up, which is often just after the real mistake. Messages differ by engine. In current Chrome and Node.js, JSON.parse errors look like Unexpected token '}', ..."a": 1,}" is not valid JSON; Firefox says JSON.parse: expected double-quoted property name at line 1 column 10; Python raises json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 10 (char 9).
| Message (paraphrased) | Usual cause |
|---|---|
Unexpected token } or ] | Trailing comma before the closing bracket. |
| Expected double-quoted property name | Unquoted key, single-quoted key, or trailing comma in an object. |
Unexpected token ' | Single-quoted string. |
Unexpected token / | A // or /* */ comment. |
Unexpected token N / u / T | NaN, undefined, or Python's True / None. |
| Unexpected end of JSON input | Truncated text: a missing closing bracket, an empty string, or a cut-off response. |
Unexpected token < | You parsed an HTML page (often an error or login page), not JSON. |
| Bad control character in string literal | A raw tab or newline inside a string. Escape it as \t or \n. |
The fixes, one by one
Trailing commas
JavaScript, Python and most config formats allow a comma after the last element; JSON does not. They usually appear after deleting the last item of a list by hand. Remove the comma before every } and ].
Single quotes and unquoted keys
Strings and keys must use double quotes. This often happens when someone prints a Python dict with print(d) or str(d) instead of json.dumps(d), or copies a JavaScript object literal. Fix it at the source by serializing properly:
import json
data = {"active": True, "owner": None}
print(str(data)) # {'active': True, 'owner': None} <- not JSON
print(json.dumps(data)) # {"active": true, "owner": null}Comments
JSON has no comments. If your file is a config that supports them (VS Code's settings.json, tsconfig.json), it is JSONC, not JSON, and a strict parser will reject it. Strip the comments or parse with a JSONC-aware library. See JSON vs JSON5 vs JSONC for which tools accept what.
NaN, Infinity and undefined
JSON numbers must be finite. In JavaScript, JSON.stringify already converts NaN and Infinity to null and drops undefined object properties, so if you see them in output, something built the string by hand. Python's json.dumps writes NaN by default; pass allow_nan=False to raise an error instead, and replace the values with null first.
Escapes inside strings
Only these escapes are valid: \", \\, \/, \b, \f, \n, \r, \t and \uXXXX. Windows paths are the classic trap: "C:\new" is valid but means a newline, while "C:\data" is invalid because \d is not an escape. Write "C:\\data", or use forward slashes.
Numbers
No leading zeros (007), no leading +, no hex, no trailing decimal point (1.). Values with meaningful leading zeros, such as ZIP codes and IDs, should be strings anyway. Very large integers are valid JSON but JavaScript's JSON.parse silently loses precision above 2^53 - 1 (9007199254740991), so send big IDs as strings.
Unexpected end of input and HTML responses
If parsing an API response fails at position 0 with <, log the raw body: you are getting HTML. If it fails at the end, the response was truncated or empty. Check the status code and Content-Type header before calling response.json():
const res = await fetch(url);
const text = await res.text();
if (!res.ok || !res.headers.get("content-type")?.includes("json")) {
throw new Error("Expected JSON, got " + res.status + ": " + text.slice(0, 200));
}
const data = JSON.parse(text);Find the error fast
- Paste the text into the validator. It highlights the line and column and explains the problem in plain words.
- Look a few characters before the reported position, especially for trailing commas and missing commas.
- For many small mistakes at once, use the JSON fixer. It repairs common mistakes such as trailing commas, quotes and comments and shows a diff, so you can review each change.
- Once it parses, run the formatter so the structure is readable and mistakes are easier to spot next time.
If the broken JSON came from ChatGPT or another model, there are extra failure modes such as Markdown fences and truncated output; see how to fix broken JSON from LLMs.
FAQ
Why does my JSON say "Unexpected token"?
The parser found a character that is not allowed at that position. The most common causes are a trailing comma, a single quote, a comment, or an HTML page where JSON was expected. Check just before the reported position.
Are trailing commas allowed in JSON?
No. RFC 8259 does not allow them in objects or arrays. JSON5 and many JSONC parsers accept them, but standard JSON.parse and Python's json module reject them.
Can JSON use single quotes?
No. Strings and object keys must use double quotes. Single quotes are valid in JSON5 but not JSON.
How do I fix invalid JSON automatically?
Use a JSON fixer that repairs common mistakes and shows what it changed. Review the diff: automatic repair can guess wrong when text was truncated.
What does "Unexpected end of JSON input" mean?
The text ended before the structure was complete: an empty string, a missing closing bracket or brace, or a truncated response. Log the raw text to see where it stops.

