X Xerobit

JSON Parse Errors — SyntaxError, Common Causes, and Safe Parsing

JSON.parse throws SyntaxError for any malformed input. Learn the most common JSON parse errors, how to debug them, safe parsing with try/catch, and handling partial/streaming...

Mian Ali Khalid · · 4 min read
Use the tool
JSON Formatter
Format, validate, and beautify JSON online. 100% client-side — your data never leaves your browser.
Open JSON Formatter →

JSON.parse() throws a SyntaxError for any malformed JSON. The error messages are not always descriptive, but the causes are predictable.

Validate and fix JSON with the JSON Formatter.

The most common JSON parse errors

// 1. Trailing comma (invalid in JSON, valid in JS objects):
JSON.parse('{"name": "Alice",}');  // SyntaxError: Unexpected token }

// 2. Single quotes instead of double quotes:
JSON.parse("{'name': 'Alice'}");   // SyntaxError: Unexpected token '

// 3. Unquoted keys:
JSON.parse('{name: "Alice"}');     // SyntaxError: Unexpected token n

// 4. undefined value (not valid JSON):
JSON.parse('{"value": undefined}'); // SyntaxError

// 5. Comments (JSON doesn't support comments):
JSON.parse('{ // comment\n"key": 1}'); // SyntaxError

// 6. NaN or Infinity:
JSON.parse('{"n": NaN}');          // SyntaxError

// 7. Hexadecimal numbers:
JSON.parse('{"n": 0xFF}');         // SyntaxError

// 8. Control characters in strings:
JSON.parse('{"s": "line1\nline2"}'); // SyntaxError (literal newline in string)
// Fix: use escaped sequence
JSON.parse('{"s": "line1\\nline2"}'); // OK

// 9. Byte Order Mark (BOM) at start:
JSON.parse('{"key": "value"}'); // SyntaxError
// Fix: text.replace(/^/, '')

Safe parsing with try/catch

// Basic safe parse:
function safeParseJSON(text) {
  try {
    return { data: JSON.parse(text), error: null };
  } catch (e) {
    return { data: null, error: e.message };
  }
}

const { data, error } = safeParseJSON(responseText);
if (error) {
  console.error('Invalid JSON:', error);
} else {
  console.log(data);
}
// With type validation:
function parseJSON(text, fallback = null) {
  try {
    const parsed = JSON.parse(text);
    return parsed;
  } catch {
    return fallback;
  }
}

// Parse with expected type guard:
function parseJSONAs(text, guard) {
  const parsed = parseJSON(text);
  if (parsed === null || !guard(parsed)) {
    throw new Error('JSON does not match expected shape');
  }
  return parsed;
}

// Usage:
const user = parseJSONAs(response, (v) =>
  typeof v === 'object' && v !== null && typeof v.name === 'string'
);

Debugging the error location

SyntaxError messages vary by browser/engine but often include a position:

// V8 (Node.js/Chrome):
// "SyntaxError: Expected ',' or '}' after property value in JSON at position 15"
// "SyntaxError: Unexpected token } at position 20"

function findJSONError(text) {
  try {
    JSON.parse(text);
    return null;
  } catch (e) {
    // Extract position from error message if available:
    const match = e.message.match(/position (\d+)/);
    if (match) {
      const pos = parseInt(match[1]);
      const before = text.slice(Math.max(0, pos - 20), pos);
      const after = text.slice(pos, pos + 20);
      return {
        message: e.message,
        position: pos,
        context: `...${before}>>>HERE<<<${after}...`,
      };
    }
    return { message: e.message };
  }
}

Common real-world scenarios

// 1. API response that's HTML (error page) instead of JSON:
async function fetchJSON(url) {
  const res = await fetch(url);
  const contentType = res.headers.get('content-type');
  
  if (!contentType?.includes('application/json')) {
    throw new Error(`Expected JSON, got: ${contentType}`);
  }
  
  const text = await res.text();
  
  try {
    return JSON.parse(text);
  } catch (e) {
    throw new Error(`Invalid JSON from ${url}: ${e.message}\nFirst 200 chars: ${text.slice(0, 200)}`);
  }
}

// 2. localStorage that might contain corrupted data:
function getStoredUser() {
  const raw = localStorage.getItem('user');
  if (!raw) return null;
  
  try {
    return JSON.parse(raw);
  } catch {
    localStorage.removeItem('user');  // Clear corrupted data
    return null;
  }
}

// 3. Parse JSON with comments (JSONC format):
function parseJSONC(text) {
  // Remove single-line and block comments:
  const stripped = text
    .replace(/\/\/[^\n]*/g, '')      // // comments
    .replace(/\/\*[\s\S]*?\*\//g, '') // /* */ comments
    .replace(/,\s*([}\]])/g, '$1');  // Trailing commas
  
  return JSON.parse(stripped);
}

Using JSON.parse reviver

// The reviver function transforms values during parsing:
const json = '{"createdAt":"2026-05-12T14:30:00Z","count":"42"}';

const parsed = JSON.parse(json, (key, value) => {
  // Auto-convert ISO date strings to Date objects:
  if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T/.test(value)) {
    return new Date(value);
  }
  // Convert numeric strings to numbers:
  if (key === 'count' && typeof value === 'string') {
    return parseInt(value, 10);
  }
  return value;
});

parsed.createdAt instanceof Date;  // true
typeof parsed.count === 'number';  // true

Python: json.loads errors

import json

# Common Python JSON errors:
try:
    data = json.loads('{"key": undefined}')
except json.JSONDecodeError as e:
    print(f"Error at line {e.lineno}, col {e.colno}: {e.msg}")
    # Error at line 1, col 9: Expecting value

# Safe loading:
def safe_json_load(text: str, default=None):
    try:
        return json.loads(text)
    except json.JSONDecodeError:
        return default

Related posts

Related tool

JSON Formatter

Format, validate, and beautify JSON online. 100% client-side — your data never leaves your browser.

Written by Mian Ali Khalid. Part of the Data & Format pillar.