How to Fix JSON Parse Errors: Every Common Error Explained
You're calling an API, reading a config file, or processing user input — and your code throws a JSON parse error. The error message is cryptic, the stack trace points to JSON.parse(), and you're staring at a blob of text wondering what's wrong. Sound familiar?
This guide covers every common JSON parse error you'll encounter, explains exactly what causes it, and shows you how to fix it. Bookmark this page — you'll come back to it.
The Quick Fix: Validate First
Before debugging line by line, paste your JSON into a JSON validator. A good validator pinpoints the exact line and character where the error occurs and suggests a fix. This solves 90% of cases in under 10 seconds.
If you need to fix it programmatically or understand the root cause, read on.
Error #1: "Unexpected token" / "Unexpected token o in JSON at position 0"
This is the single most common JSON parse error. You'll see it in every language:
- JavaScript:
SyntaxError: Unexpected token o in JSON at position 0 - Python:
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 - Java:
com.google.gson.JsonSyntaxException: Expected BEGIN_OBJECT but was STRING
Cause: You're parsing something that isn't JSON
The "token o at position 0" variant is a dead giveaway — you're passing a JavaScript object to JSON.parse() instead of a JSON string. The parser sees [object Object] and chokes on the o.
// ❌ Bug: data is already an object, not a string
const data = { name: "Alice" };
JSON.parse(data); // SyntaxError: Unexpected token o
// ✅ Fix: data is already parsed — use it directly
const data = { name: "Alice" };
console.log(data.name); // "Alice"
// ✅ Or if you actually need to parse a string:
const jsonString = '{"name": "Alice"}';
JSON.parse(jsonString); // worksOther causes of "Unexpected token"
- HTML error page: Your API returned an HTML error page (starting with
<) instead of JSON. Check the response status code and content-type header. - Empty string:
JSON.parse("")throws "Unexpected end of JSON input". Check that the response body isn't empty. - Undefined/null:
JSON.parse(undefined)throws "Unexpected token u at position 0". - BOM character: Some files start with a UTF-8 BOM (
) that's invisible but breaks the parser. Strip it:text.replace(/^/, '').
// Defensive parsing pattern
function safeJsonParse(text) {
if (!text || typeof text !== 'string') {
return { error: 'Input is not a string', data: null };
}
try {
// Strip BOM if present
const clean = text.replace(/^\uFEFF/, '');
return { error: null, data: JSON.parse(clean) };
} catch (e) {
return { error: e.message, data: null };
}
}Error #2: "Unexpected end of JSON input"
The parser reached the end of the string before finding a complete JSON structure.
Cause: Truncated or incomplete JSON
// ❌ Missing closing brace
JSON.parse('{"name": "Alice"');
// SyntaxError: Unexpected end of JSON input
// ❌ Empty string
JSON.parse('');
// SyntaxError: Unexpected end of JSON input
// ✅ Complete JSON
JSON.parse('{"name": "Alice"}');Common scenarios
- Network timeout: The response was cut off mid-transfer. Check your timeout settings and the complete response length.
- Buffer size limit: The response was larger than your client's buffer. Increase the limit or stream the response.
- String concatenation bug: You built the JSON string by concatenating parts and missed the closing bracket.
- File read error: You read a file but it was empty or partially written.
# Python: check if response is complete before parsing
import json
response = requests.get("https://api.example.com/data")
# Check status first
if response.status_code != 200:
print(f"HTTP error: {response.status_code}")
else:
text = response.text
if not text:
print("Empty response body")
else:
try:
data = json.loads(text)
except json.JSONDecodeError as e:
print(f"Parse error at line {e.lineno}, col {e.colno}: {e.msg}")Error #3: "Expected property name or }" — Trailing Commas
JSON does not allow trailing commas. This is one of the most frequent mistakes because JavaScript, Python, and most config formats do allow them.
// ❌ Trailing comma after last element
{
"name": "Alice",
"age": 30, ← trailing comma
}
// ❌ Trailing comma in array
{
"skills": ["JavaScript", "React",] ← trailing comma
}
// ✅ No trailing commas
{
"name": "Alice",
"age": 30
}How to find trailing commas
Search for the regex pattern ,\s*[\]}] in your JSON. This matches a comma followed by optional whitespace and then a closing bracket or brace — which is always invalid in JSON.
# Find trailing commas in a file
grep -n ',\s*[}\]]' data.jsonError #4: Single Quotes Instead of Double Quotes
JSON strictly requires double quotes for all strings and property names. Single quotes, backticks, and unquoted keys are all invalid.
// ❌ Single quotes — invalid JSON
{'name': 'Alice', 'age': 30}
// ❌ Unquoted keys — invalid JSON
{name: "Alice", age: 30}
// ❌ Backtick strings — invalid JSON
{"name": `Alice`}
// ✅ Double quotes only
{"name": "Alice", "age": 30}Why does this happen?
Usually because someone copied a JavaScript object literal and assumed it was JSON. JavaScript objects look similar to JSON but have looser syntax rules. If you're generating JSON from code, always use your language's JSON serialization function — never build JSON strings by hand.
// ❌ Don't hand-build JSON strings
const json = "{'name': '" + name + "'}";
// ✅ Use JSON.stringify
const json = JSON.stringify({ name: name });Error #5: Comments in JSON
JSON does not support comments of any kind — neither // line comments nor /* */ block comments. This surprises many developers because JSON looks like JavaScript, and JavaScript supports both.
// ❌ Comments are invalid JSON
{
// This is the user's name
"name": "Alice",
/* Age in years */
"age": 30
}
// ✅ Remove all comments
{
"name": "Alice",
"age": 30
}Workarounds
- Use JSON5: If you control the parser, JSON5 is a superset of JSON that supports comments, trailing commas, and single quotes.
- Use JSONC: VS Code uses "JSON with Comments" (
.jsonc) for its config files. TypeScript'stsconfig.jsonalso supports this. - Strip comments before parsing: Use a preprocessing step to remove comments before passing the string to
JSON.parse(). - Use a different format: If you need comments, consider YAML or TOML for configuration files.
Error #6: Unescaped Special Characters in Strings
Certain characters must be escaped inside JSON strings. Unescaped control characters, newlines, tabs, and backslashes will cause parse errors.
// ❌ Unescaped newline in string
{"message": "Line 1
Line 2"}
// ❌ Unescaped backslash
{"path": "C:\Users\Alice"} ← needs double escaping
// ❌ Unescaped tab
{"data": "col1 col2"}
// ✅ Properly escaped
{"message": "Line 1\nLine 2"}
{"path": "C:\\Users\\Alice"}
{"data": "col1\tcol2"}Characters that must be escaped in JSON strings
| Character | Escape sequence | Description |
|---|---|---|
" | \" | Double quote |
\ | \\ | Backslash |
| Newline | \n | Line feed |
| Tab | \t | Horizontal tab |
| Carriage return | \r | Carriage return |
| Backspace | \b | Backspace |
| Form feed | \f | Form feed |
| Unicode | \uXXXX | Unicode code point |
Error #7: Invalid Number Formats
JSON has strict rules for numbers that differ from most programming languages.
// ❌ Leading zeros (not allowed)
{"code": 0123}
// ❌ Leading plus sign
{"value": +42}
// ❌ Hex numbers
{"color": 0xFF0000}
// ❌ NaN, Infinity, -Infinity (not valid JSON)
{"result": NaN}
{"limit": Infinity}
// ❌ Octal numbers
{"permissions": 0755}
// ✅ Valid JSON numbers
{"code": 123}
{"value": 42}
{"color": 16711680}
{"result": null}
{"pi": 3.14159}
{"exponent": 1.5e10}The NaN / Infinity trap
In JavaScript, JSON.stringify() silently converts NaN, Infinity, and -Infinity to null. This means you lose data without any error on the serialization side — and get surprised when reading it back.
const data = { value: NaN, limit: Infinity };
JSON.stringify(data);
// '{"value":null,"limit":null}' ← silent data loss!
// Use a replacer to catch this
JSON.stringify(data, (key, value) => {
if (Number.isNaN(value)) return "NaN";
if (value === Infinity) return "Infinity";
return value;
});Error #8: Duplicate Keys
The JSON specification says behavior with duplicate keys is undefined — different parsers handle it differently.
// ⚠️ Duplicate key "name" — behavior is undefined
{
"name": "Alice",
"age": 30,
"name": "Bob"
}
// JavaScript: last value wins → name = "Bob"
// Python: last value wins → name = "Bob"
// Some strict parsers: errorWhile most parsers silently accept duplicates (last value wins), this is almost always a bug. Duplicates usually come from manual editing mistakes or merging two JSON objects incorrectly. Our JSON validator warns about duplicate keys.
Error #9: Wrong Content-Type from API
Your code expects JSON, but the server sent something else — HTML, plain text, XML, or an empty response. This is especially common when:
- The server returned a 404 or 500 error page (HTML) instead of a JSON error response
- A proxy or CDN intercepted the request and returned its own error page
- The API requires authentication and returned a login page
- You hit a rate limit and got a plain-text "Too Many Requests" response
// Always check the content-type before parsing
async function fetchJson(url) {
const response = await fetch(url);
// Check status
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
// Check content-type
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
const text = await response.text();
throw new Error(
`Expected JSON but got ${contentType}. Body: ${text.substring(0, 200)}`
);
}
return response.json();
}Error #10: Encoding Issues
JSON must be UTF-8 encoded (RFC 8259). Other encodings like UTF-16, Latin-1, or Windows-1252 can cause parse errors or corrupted data.
- BOM (Byte Order Mark): A
character at the start of the file. Strip it before parsing. - Non-UTF-8 encoding: If you read a file with the wrong encoding, special characters become garbled and may break JSON syntax.
- Mojibake: Text that was encoded in one format and decoded in another produces garbage characters like
éinstead ofé.
# Python: explicitly read as UTF-8
with open('data.json', encoding='utf-8') as f:
data = json.load(f)
# Node.js: read as UTF-8 and strip BOM
const fs = require('fs');
const text = fs.readFileSync('data.json', 'utf8').replace(/^\uFEFF/, '');
const data = JSON.parse(text);Quick Reference: Error Messages by Language
| Problem | JavaScript | Python |
|---|---|---|
| Not a string | Unexpected token o at position 0 | the JSON object must be str |
| Empty input | Unexpected end of JSON input | Expecting value: line 1 column 1 |
| Trailing comma | Expected property name or '}' | Expecting property name |
| Single quotes | Unexpected token ' | Expecting property name enclosed in double quotes |
| Unescaped newline | Unexpected token (newline) | Invalid control character |
| HTML response | Unexpected token < | Expecting value: line 1 column 1 |
Prevention: Stop JSON Parse Errors Before They Happen
- Never build JSON by hand. Always use
JSON.stringify(),json.dumps(), or your language's equivalent. String concatenation is the #1 source of malformed JSON. - Validate at the boundary. Validate JSON when it enters your system — from APIs, file reads, user input, message queues. Don't trust that upstream data is well-formed.
- Check response status and content-type before calling
JSON.parse(). A 500 error page is not JSON. - Use a linter. Configure your editor or CI pipeline to lint JSON files. VS Code flags JSON errors in real time.
- Use TypeScript or schema validation. Type checking catches structural issues at compile time. JSON Schema catches them at runtime.
- Log the raw input on parse failure. When a parse error occurs, log the first 500 characters of the input. This makes debugging drastically faster.
// Production-ready parse wrapper with logging
function parseJson(input, context = 'unknown') {
if (typeof input !== 'string') {
console.error(`[JSON] ${context}: expected string, got ${typeof input}`);
return null;
}
try {
return JSON.parse(input.replace(/^\uFEFF/, ''));
} catch (e) {
console.error(
`[JSON] ${context}: ${e.message}. Input preview: ${input.substring(0, 500)}`
);
return null;
}
}Tools for Debugging JSON Parse Errors
- JSON Validator — paste your JSON and get the exact error location with fix suggestions.
- JSON Formatter — format messy JSON to make structural issues visible at a glance.
- JSON Diff — compare expected vs. actual JSON to spot what's different.
- Browser DevTools — the Network tab shows raw API responses. Check the Response tab to see what the server actually sent.
- jq — command-line JSON processor.
echo '...' | jq .quickly validates and formats JSON in the terminal.
Try it now
Paste your broken JSON into our validator — it'll tell you exactly what's wrong and how to fix it.
Open JSON Validator🔗 Related Tools & Resources
Explore these related JSON tools and guides