How to Fix Broken JSON Without Understanding the Error — Practical Guide

Sometimes you receive malformed JSON from an API, legacy system, or AI-generated output and need to fix it fast — even if you do not understand why it is broken. This guide gives you practical tools and patterns to fix common JSON errors automatically, from quick one-liners to fully automated repair pipelines, with exact error messages mapped to exact fixes.

jsonrepair

npm package that fixes most JSON automatically

jq

command-line tool to validate and reformat JSON

Python

json module gives precise error location

95%+

of common JSON errors fixed automatically by jsonrepair

1

Quick Fix — Use jsonrepair Library (Node.js)

The jsonrepair npm package fixes over 95% of common JSON issues automatically without any configuration. Install it once and call it on any broken JSON string:

bashinstall.sh
# Install once
npm install jsonrepair

# Or use globally from CLI
npm install -g jsonrepair
javascriptjsonrepair-examples.js
import { jsonrepair } from 'jsonrepair';

// Fix trailing commas (most common issue)
jsonrepair('{"name":"Alice","age":30,}')
// → '{"name":"Alice","age":30}'

// Fix single quotes → double quotes
jsonrepair("{'name':'Alice'}")
// → '{"name":"Alice"}'

// Fix unquoted keys
jsonrepair('{name:"Alice",age:30}')
// → '{"name":"Alice","age":30}'

// Fix missing quotes on string values
jsonrepair('{"status":active}')
// → '{"status":"active"}'

// Fix concatenated JSON objects (wraps in array)
jsonrepair('{"a":1}{"b":2}')
// → '[{"a":1},{"b":2}]'

// Fix truncated/incomplete JSON (adds missing brackets)
jsonrepair('{"name":"Alice","items":["a","b"')
// → '{"name":"Alice","items":["a","b"]}'

// Fix Python-style literals
jsonrepair('{"active": True, "data": None, "missing": NaN}')
// → '{"active": true, "data": null, "missing": null}'

// Fix comments (strips them)
jsonrepair('{"name": "Alice" /* primary user */}')
// → '{"name": "Alice"}'
bashrepair-file.sh
# Repair a JSON file and save the output
npx jsonrepair broken.json > fixed.json

# Pipe from stdin
cat broken.json | npx jsonrepair > fixed.json

# Use in a Node.js script
node -e "
const {jsonrepair} = require('jsonrepair');
const fs = require('fs');
const broken = fs.readFileSync('broken.json', 'utf8');
fs.writeFileSync('fixed.json', jsonrepair(broken));
console.log('Repaired successfully');
"
2

Using Python to Find the Exact Error Location

Python's built-in JSON module gives you the exact line and column of the error, which is invaluable for debugging large JSON files where you cannot eyeball the problem:

pythonfind_json_error.py
import json

broken_json = '''
{
  "name": "Alice",
  "age": 30,
  "tags": ["admin", "user",],
  "active": True
}
'''

try:
    data = json.loads(broken_json)
    print("Valid JSON:", data)
except json.JSONDecodeError as e:
    print(f"Error: {e.msg}")
    print(f"Line: {e.lineno}, Column: {e.colno}")
    print(f"At character position: {e.pos}")

    # Show the problematic line with a visual pointer
    lines = broken_json.split('\n')
    if e.lineno <= len(lines):
        line = lines[e.lineno - 1]
        print(f"Problem line: {line!r}")
        print(" " * (e.colno - 1) + "^--- error here")

# Output:
# Error: Expecting property name enclosed in double quotes
# Line: 5, Column: 29
# Problem line: '  "tags": ["admin", "user",],'
#                                             ^--- error here

Python Error Messages Decoded

"Expecting property name enclosed in double quotes" means trailing comma before closing brace or bracket. "Unexpected end of JSON input" means the JSON is truncated. "Expecting value" means a key exists but the value is missing or invalid. "Extra data" means multiple JSON objects were concatenated without an array wrapper.

3

The 5 Most Common JSON Mistakes and Their Fixes

Invalid JSON (5 common issues)

❌ Bad
// 1. Trailing commas (most common — not allowed in JSON spec)
{"name": "Alice", "age": 30,}
["a", "b", "c",]

// 2. Single quotes instead of double quotes
{'name': 'Alice', 'active': 'true'}

// 3. Unquoted property keys (valid JavaScript, not valid JSON)
{name: "Alice", age: 30}

// 4. Python/JavaScript runtime literals instead of JSON values
{"active": True, "data": None, "count": NaN, "big": Infinity}

// 5. Comments (JSON spec explicitly forbids them)
{
  // This is the user object
  "name": "Alice" /* primary user */
}

Valid JSON (corrected)

✅ Good
// 1. Remove trailing commas
{"name": "Alice", "age": 30}
["a", "b", "c"]

// 2. Use double quotes everywhere
{"name": "Alice", "active": "true"}

// 3. Quote all property keys
{"name": "Alice", "age": 30}

// 4. Use JSON-compliant values only
{"active": true, "data": null, "count": 0, "big": 1e308}

// 5. No comments allowed — use a _comment field if needed
{
  "_comment": "This is the user object",
  "name": "Alice"
}
4

Error Message to Fix Cheat Sheet

ItemError Message You SeeWhat It Means and How to Fix
Unexpected token , in JSONTrailing comma before ] or }Search for ,] or ,} and remove the comma
Unexpected token ' in JSONSingle quotes used instead of doubleReplace all single quotes with double quotes
Unexpected token T in JSONPython True used instead of JSON trueReplace True→true, False→false, None→null
Unexpected end of JSON inputJSON is truncated — missing closing bracketsCount opening vs closing braces and brackets — add missing ones
Unexpected token at position 0BOM character or whitespace before opening {Strip BOM: text.replace(/^\uFEFF/, "")
Extra data after JSON valueMultiple JSON objects concatenatedWrap in [ ] to make a JSON array, or split and parse separately
Property name must be a stringUnquoted key — JavaScript object syntaxAdd double quotes around every property name
5

Command Line Validation with jq

bashjq-validation.sh
# Install jq
brew install jq          # macOS
apt-get install jq       # Ubuntu/Debian
choco install jq         # Windows (Chocolatey)

# Validate and pretty-print (shows error with line number if invalid)
echo '{"name":"Alice","age":30}' | jq .

# Validate a file
cat data.json | jq .

# Validate without output (exit code 0=valid, 1=invalid)
cat data.json | jq . > /dev/null && echo "Valid" || echo "Invalid"

# Find error in large file
cat data.json | jq . 2>&1 | grep "parse error"

# Extract specific field to verify parsing
cat data.json | jq '.users[0].name'

# Compact output (minify valid JSON)
cat data.json | jq -c .

# Sort keys alphabetically (useful for diffing JSON files)
cat data.json | jq -S .
6

Automated Repair Pipeline for Batch Processing

For processing batches of potentially-broken JSON from external sources (APIs, scrapers, user uploads), use this complete repair pipeline with progressive fallback:

pythonjson_repair_pipeline.py
import json
import re
import subprocess
from typing import Optional

def try_parse(text: str) -> Optional[dict]:
    """Try to parse JSON. Returns None if it fails."""
    try:
        return json.loads(text)
    except json.JSONDecodeError:
        return None

def fix_python_literals(text: str) -> str:
    """Replace Python-style literals with JSON equivalents."""
    text = text.replace('True', 'true')
    text = text.replace('False', 'false')
    text = text.replace('None', 'null')
    text = re.sub(r'\bNaN\b', 'null', text)
    text = re.sub(r'\bInfinity\b', '1e308', text)
    return text

def strip_comments(text: str) -> str:
    """Remove JavaScript-style comments from JSON."""
    text = re.sub(r'//.*?$', '', text, flags=re.MULTILINE)
    text = re.sub(r'/\*.*?\*/', '', text, flags=re.DOTALL)
    return text

def fix_trailing_commas(text: str) -> str:
    """Remove trailing commas before } and ]."""
    return re.sub(r',\s*([}\]])', r'\1', text)

def repair_with_jsonrepair(text: str) -> str:
    """Use jsonrepair npm package as final fallback."""
    try:
        result = subprocess.run(
            ['npx', 'jsonrepair'],
            input=text, capture_output=True, text=True, timeout=10
        )
        if result.returncode == 0:
            return result.stdout
    except (subprocess.TimeoutExpired, FileNotFoundError):
        pass
    return text

def process_json(raw: str) -> dict:
    """Parse JSON with progressive repair strategy."""
    # Step 1: Parse as-is (fastest path)
    if result := try_parse(raw):
        return result

    # Step 2: Strip BOM
    cleaned = raw.lstrip('\ufeff')
    if result := try_parse(cleaned):
        return result

    # Step 3: Fix Python literals
    cleaned = fix_python_literals(cleaned)
    if result := try_parse(cleaned):
        return result

    # Step 4: Strip comments
    cleaned = strip_comments(cleaned)
    if result := try_parse(cleaned):
        return result

    # Step 5: Fix trailing commas
    cleaned = fix_trailing_commas(cleaned)
    if result := try_parse(cleaned):
        return result

    # Step 6: Nuclear option — use jsonrepair
    repaired = repair_with_jsonrepair(raw)
    if result := try_parse(repaired):
        return result

    # Nothing worked — raise with diagnostics
    try:
        json.loads(raw)
    except json.JSONDecodeError as e:
        raise ValueError(
            f"Could not repair JSON. Error at line {e.lineno}, col {e.colno}: {e.msg}"
        ) from e

# Usage:
broken = '{"name": "Alice", active: True, tags: ["admin",],}'
data = process_json(broken)
print(data)  # {'name': 'Alice', 'active': True, 'tags': ['admin']}
7

TypeScript Repair Utility

typescriptparseJsonSafely.ts
/**
 * Try to parse JSON, repairing common issues automatically.
 * Falls back through repair steps before throwing.
 */
export async function parseJsonSafely<T = unknown>(input: string): Promise<T> {
  // Step 1: Try as-is
  try { return JSON.parse(input) as T; } catch {}

  // Step 2: Strip BOM and leading whitespace
  let cleaned = input.replace(/^/, '').trim();

  // Step 3: Fix Python literals
  cleaned = cleaned
    .replace(/\bTrue\b/g, 'true')
    .replace(/\bFalse\b/g, 'false')
    .replace(/\bNone\b/g, 'null')
    .replace(/\bNaN\b/g, 'null');

  // Step 4: Remove trailing commas before } or ]
  cleaned = cleaned.replace(/,\s*([}\]])/g, '$1');

  // Step 5: Try repaired version
  try { return JSON.parse(cleaned) as T; } catch {}

  // Step 6: Use jsonrepair
  const { jsonrepair } = await import('jsonrepair');
  try {
    return JSON.parse(jsonrepair(input)) as T;
  } catch (e) {
    throw new Error(`Failed to parse JSON after all repair attempts: ${String(e)}`);
  }
}

// Usage:
const data = await parseJsonSafely<{ name: string }>('{"name": "Alice",}');
console.log(data.name); // Alice
8

Identifying Specific Error Types at a Glance

"Unexpected token" errors

Usually means: wrong quote type (single vs double), unquoted key, or illegal character. Look at the character at the reported position — it will be the culprit. The error message often includes the unexpected character in quotes.

"Unexpected end of JSON input"

The JSON is cut off or incomplete. Common when API responses are streamed or truncated by a length limit. Count the opening and closing brace and bracket pairs — one set is missing its closing half.

"Expected , or }" errors

A comma is missing between properties, or the previous value did not close properly. Walk backwards from the error position to find where the structure broke.

"Circular structure to JSON"

This happens at JSON.stringify time. Your JavaScript object has circular references (object A references B which references A). Use a replacer function or the flatted package to handle circular structures.

Encoding issues (BOM, null bytes)

UTF-8 BOM character at the start of a file, null bytes, or non-UTF8 sequences can break parsing. Strip with: text.replace(/^\uFEFF/, "").replace(/\u0000/g, "").

JSON.stringify returns undefined

This happens when you pass undefined itself, a function, or a Symbol to JSON.stringify. These types are not serializable. Use JSON.stringify(value) ?? "null" as a safe fallback.

9

Preventing Broken JSON in Your Own Code

1

Never build JSON by hand with string concatenation

Use JSON.stringify() in JavaScript, json.dumps() in Python, or your language equivalent. String concatenation is the top source of malformed JSON in homegrown code — one unescaped quote breaks everything.

2

Validate at API boundaries

When receiving JSON from external APIs, wrap the parse in try/catch and log the raw response on failure. This makes debugging 10x easier than a cryptic downstream error with no context.

3

Use Zod or similar for structure validation

JSON.parse only validates syntax, not structure. Libraries like Zod let you define a schema and validate the parsed object — catching wrong types and missing required fields that JSON.parse misses.

4

Handle partial responses from streaming APIs

When consuming streaming JSON (SSE, chunked HTTP), buffer the incoming data and only parse when you have a complete object. Streaming APIs frequently send partial JSON that is invalid until the full chunk arrives.

5

Test with edge case inputs

Include empty object {}, empty array [], null values, nested structures, and unicode strings in your test suite for any JSON parsing code. These are where most JSON handling bugs hide.

Use an online JSON tool for quick fixes

Paste your broken JSON at unblockdevs.com/tools/json for instant repair and explanation of every error found. Highlights the exact problematic character, shows the fix, and lets you copy the corrected JSON immediately — no installation required.

Frequently Asked Questions