Blog post
JSON Error Handling Best Practices
Handle JSON errors gracefully — parse failures, API response errors, schema mismatches, and network issues with code examples.
Shashank Jain
Author


Article
Why JSON Error Handling Matters
JSON errors are among the most common runtime failures in web applications. An API returns HTML instead of JSON, a user pastes malformed input, or a network error truncates a response — any of these crashes an app that does not handle errors properly.
Safe JSON.parse in JavaScript
// Never do this — crashes on invalid input
const data = JSON.parse(userInput);
// Always do this
function safeParseJSON(str, fallback = null) {
try {
return JSON.parse(str);
} catch (e) {
console.error('JSON parse failed:', e.message);
return fallback;
}
}
const data = safeParseJSON(userInput, {});Handling API JSON Errors
async function fetchJSON(url) {
const res = await fetch(url);
// Check HTTP status before parsing
if (!res.ok) {
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
}
// Check Content-Type — API might return HTML on error
const contentType = res.headers.get('content-type');
if (!contentType?.includes('application/json')) {
const text = await res.text();
throw new Error(`Expected JSON, got ${contentType}: ${text.slice(0, 200)}`);
}
return res.json();
}
// Usage
try {
const data = await fetchJSON('/api/users');
} catch (e) {
console.error('Failed to fetch:', e.message);
}TypeScript: Type-Safe JSON Parsing
import { z } from 'zod';
const UserSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string().email()
});
type User = z.infer<typeof UserSchema>;
async function getUser(id: number): Promise<User> {
const res = await fetch(`/api/users/${id}`);
const raw = await res.json();
return UserSchema.parse(raw); // throws ZodError if invalid
}Python Error Handling
import json
from typing import Any, Optional
def safe_parse(text: str, fallback: Any = None) -> Any:
try:
return json.loads(text)
except json.JSONDecodeError as e:
print(f'JSON error at line {e.lineno}, col {e.colno}: {e.msg}')
return fallback
# Requests library
import requests
def fetch_json(url: str) -> Optional[dict]:
try:
res = requests.get(url, timeout=10)
res.raise_for_status() # Raises for 4xx/5xx
return res.json()
except requests.exceptions.JSONDecodeError:
print('Response is not valid JSON')
except requests.exceptions.HTTPError as e:
print(f'HTTP error: {e}')
except requests.exceptions.RequestException as e:
print(f'Network error: {e}')
return NoneCommon Error Patterns
| Error | Cause | Fix |
|---|---|---|
| SyntaxError: Unexpected token < | API returned HTML error page | Check Content-Type header before parsing |
| SyntaxError: Unexpected end | Truncated response | Check network, increase timeout |
| TypeError: Cannot read property of null | Parsed null, not object | Default to {} or [] after parsing |
| JSON decode error at position N | Encoding mismatch or BOM | Normalize encoding, strip BOM |
FAQ
Should I always wrap JSON.parse in try/catch?
Yes, whenever parsing untrusted or external data — user input, API responses, file contents. Skip try/catch only when the JSON comes from your own serializer in the same request/response cycle.
How do I get the line number of a JSON syntax error?
In Python, json.JSONDecodeError has lineno and colno attributes. In JavaScript, the Error message includes position info but not structured. Use a linting library like jsonlint for detailed error positions.
What is the best way to validate JSON structure after parsing?
Use Zod (TypeScript/JavaScript) or Pydantic (Python) for runtime schema validation. Both provide clear error messages and TypeScript/Python type inference from the schema.
How do I handle partial JSON responses from streaming APIs?
Buffer incoming chunks and attempt JSON.parse only when you receive the closing delimiter. For structured streaming, use NDJSON (newline-delimited JSON) — each line is a complete valid JSON object.
Why does fetch().json() fail even when the response looks right?
Common causes: Content-Type header is missing or wrong, response body is empty, or there is a BOM character at the start. Log res.text() first to inspect the raw response before parsing.
Keep reading
Recent blogs

Jun 14, 2026
JSON in C#: System.Text.Json and Newtonsoft Complete Guide
Serialize and deserialize JSON in C# using System.Text.Json and Newtonsoft.Json with practical examples.

Jun 14, 2026
JSON to Markdown Table: Convert JSON Arrays Instantly
Convert JSON arrays to Markdown tables in JavaScript, Python, and with the free online tool.

Jun 14, 2026
JSON in TypeScript: Type-Safe Parsing and Validation
Stop using any for JSON in TypeScript — use Zod, type guards, and generics for fully type-safe parsing.