Top 10 JSON Errors That Waste Developer Time — and How to Fix Them Fast
JSON errors can bring development to a halt for minutes or hours. You're debugging, searching Stack Overflow, and trying random fixes while your application is broken. This guide covers the 10 most common JSON parse errors — what causes each one, how to fix it in under a minute, and how to prevent it entirely with proper patterns.
#1
"Unexpected token <" — HTML error returned instead of JSON
5-20 min
average time wasted per JSON error
JSON.stringify
the prevention for most manual JSON errors
try-catch
required pattern for all JSON.parse() calls
Error #1 — Unexpected token <
Most common, most confusing
This error means JSON.parse() received HTML, not JSON. Your API returned an HTML error page (404, 500, or authentication redirect) instead of the expected JSON response. The < is the start of <html> or <!DOCTYPE html>.
No status check — crashes on HTML
// This silently receives an HTML error page and then crashes on parse
const response = await fetch('/api/users');
const data = await response.json(); // ❌ SyntaxError: Unexpected token '<'
// The API returned a 404 HTML page, not JSONCheck response.ok first
// Always check response.ok before parsing
const response = await fetch('/api/users');
// Check HTTP status BEFORE calling .json()
if (!response.ok) {
const text = await response.text(); // Read as text to see the actual error
throw new Error(`API error ${response.status}: ${text.slice(0, 200)}`);
}
const data = await response.json(); // ✅ Safe — response is 2xxError #2 — Unexpected end of JSON input
// ❌ Causes this error:
JSON.parse('{"name": "Alice", "age": 30') // Missing }
JSON.parse('{"items": [1, 2, 3') // Missing ]}
JSON.parse('') // Empty string
// Also happens with truncated API responses — network timeout cuts off the body
// Symptom: error at the very end of the string (the parser ran out of input)
// ✅ Fix: always use try-catch and validate non-empty response
function safeJsonParse(text) {
if (!text || text.trim() === '') {
throw new Error('Cannot parse empty response as JSON');
}
try {
return JSON.parse(text);
} catch (e) {
console.error('JSON parse failed. Input was:', text.slice(0, 500));
throw new Error(`Invalid JSON: ${e.message}`);
}
}
// Use JSON validators to find the exact position of the missing brace:
// unblockdevs.com/json-validator highlights the exact problem locationError #3 — Trailing Comma (Expected ',' or '}' after property value)
Trailing comma — invalid JSON
// ❌ JSON does NOT allow trailing commas (unlike JavaScript)
{
"name": "Alice",
"age": 30, ← trailing comma before }
}
// Also invalid in arrays:
["apple", "banana", "cherry",] ← trailing comma before ]
// JSON.parse will throw: "Unexpected token }" or "Unexpected token ]"No trailing comma + use JSON.stringify()
// ✅ No trailing commas in JSON
{
"name": "Alice",
"age": 30
}
// ✅ Arrays without trailing comma
["apple", "banana", "cherry"]
// Prevention: use JSON.stringify() — it never generates trailing commas
const json = JSON.stringify({ name: "Alice", age: 30 }); // always valid
// If receiving JSON with trailing commas (JSONC format), parse with:
// JSON5 library: JSON5.parse(jsonWithTrailingCommas)
// Or strip them: text.replace(/,\s*([}\]])/g, '$1')Errors #4-10 — Quick Reference
| Item | Error Message | Cause and Fix |
|---|---|---|
| #4 Invalid control character | Unescaped newlines, tabs in string values | Use JSON.stringify() — it escapes automatically. Manual: \n \t \r |
| #5 Single quotes used | 'value' instead of "value" | JSON requires double quotes. Replace all single quotes with double quotes. |
| #6 Comments in JSON | // or /* */ comments included | JSON has no comments. Remove all comments. Use JSONC/JSON5 if you need comments. |
| #7 Undefined value | undefined property value (not valid) | Replace with null. JSON.stringify() omits undefined keys automatically. |
| #8 NaN or Infinity | NaN, Infinity, -Infinity values | JSON has no NaN/Infinity. Replace with null or a sentinel number (-1). |
| #9 Non-string keys | {42: "value"} — numeric key | All JSON keys must be strings: {"42": "value"} |
| #10 Encoding issues | Non-UTF8 chars or BOM at start | Ensure UTF-8 encoding. Strip BOM: text.replace(/^\uFEFF/, "") |
The Root Causes — Why These Errors Happen
Building JSON manually
Manually concatenating strings to build JSON is the root cause of most JSON syntax errors (trailing commas, missing quotes, invalid characters). Always use JSON.stringify() — it handles escaping and formatting correctly every time.
Not checking API response status
Calling response.json() without first checking response.ok causes the "Unexpected token <" error when the server returns an HTML error page. Always check status codes before parsing.
Copying JSON from code with comments
JavaScript objects (with // comments, trailing commas, unquoted keys) look like JSON but aren't. If you copy a JS object literal to use as JSON, it will fail — JSON is a strict subset of JavaScript.
Truncated network responses
Large responses that time out mid-transfer produce truncated JSON causing "Unexpected end of input." Set appropriate timeouts and check Content-Length vs actual received bytes for large payloads.
Prevention Patterns That Eliminate JSON Errors
// Pattern 1: ALWAYS use JSON.stringify() — never build JSON manually
// ❌ Never do this:
const json = '{"name":"' + user.name + '","age":' + user.age + '}';
// ✅ Always do this:
const json = JSON.stringify({ name: user.name, age: user.age });
// Pattern 2: ALWAYS wrap JSON.parse() in try-catch
function safeParse(jsonString) {
try {
return { data: JSON.parse(jsonString), error: null };
} catch (error) {
return { data: null, error: error.message };
}
}
const { data, error } = safeParse(apiResponse);
if (error) console.error('JSON parse failed:', error);
// Pattern 3: ALWAYS check response.ok before .json()
async function fetchJson(url) {
const response = await fetch(url);
if (!response.ok) {
const errorText = await response.text();
throw new Error(`HTTP ${response.status}: ${errorText.slice(0, 200)}`);
}
const contentType = response.headers.get('content-type');
if (!contentType?.includes('application/json')) {
throw new Error(`Expected JSON but got ${contentType}`);
}
return response.json();
}
// Pattern 4: Validate JSON structure after parsing
function parseUser(jsonString) {
const data = JSON.parse(jsonString);
if (!data || typeof data !== 'object') throw new Error('Expected object');
if (!data.id || !data.email) throw new Error('Missing required fields');
return data;
}
// Pattern 5: For Python — use json module, not eval()
import json
# ❌ Never: eval(json_string)
# ✅ Always: json.loads(json_string) with try/except json.JSONDecodeErrorDebugging JSON Errors Step by Step
Read the error message carefully
The error message tells you exactly what went wrong: "Unexpected token <" means HTML received. "Unexpected token }" means trailing comma or extra brace. "Unexpected end of JSON input" means truncated. The token mentioned is usually the first character that confused the parser.
Print the raw string before parsing
Before JSON.parse(), log the exact string: console.log("Raw:", JSON.stringify(rawString)) or in Python print(repr(raw_string)). This reveals invisible characters, encoding issues, HTML contamination, or unexpected content that looks fine in normal logging.
Use a JSON validator to find the exact location
Paste your JSON into a validator (unblockdevs.com/json-validator, jsonlint.com) — it pinpoints the exact line and character position of the error. Much faster than reading long JSON manually to find a missing comma or brace.
Check the source — where is the JSON coming from?
Is it from an API response? Check the raw HTTP response (curl -v or Chrome DevTools Network tab → Response tab). Is it from a file? Check file encoding. Is it from user input? Validate and sanitize before parsing.
Check the Content-Type header
A server returning the wrong Content-Type header (text/html instead of application/json) usually means the endpoint returned an error page. Check the full response headers and status code. A 401 Unauthorized often returns an HTML login page, causing "Unexpected token <".
Use our JSON Fixer tool for instant repair