7 min readUpdated

10 JSON Debugging Mistakes That Waste Hours (and How to Fix Them Fast)

By Safe Local Tools Editorial

Most broken JSON is not “mysterious”—it is predictable. Once you recognize a handful of recurring mistakes, you stop chasing ghosts in server logs and start fixing structure, encoding, and assumptions in minutes instead of hours.

When an API returns Unexpected token or a pipeline silently drops configuration, the culprit is rarely “JSON itself.” More often, you are feeding the parser something that looks like JSON in an editor but violates the rules defined in RFC 8259 (often summarized alongside readable introductions such as JSON on Wikipedia). This guide walks through ten mistakes engineers hit repeatedly, explains why parsers behave the way they do, and shows how Safe Local Tools processes JSON locally in your browser—so you can format, inspect, and sanity‑check payloads without uploading secrets to a third‑party server.

OG illustration

Why JSON “works in Node” but fails in strict parsers

JavaScript developers regularly confuse JSON with JavaScript object literals. They’re related, but not interchangeable. JSON is a text interchange format with a tight grammar. JavaScript is a programming language that tolerates extra convenience features—features JSON deliberately forbids.

That mismatch creates an entire category of bugs: code runs fine during prototyping (because you never serialized it), then fails as soon as you write data to disk or exchange it over HTTP. If you want an authoritative mental model for parsing behavior in browsers, Mozilla’s JSON.parse() documentation is an excellent reference because it highlights exactly what throws and why.

There is also a social failure mode: teams share “JSON” via chat apps and browsers that subtly rewrite characters—smart quotes, stripped indentation, or wrapped formatting—so the snippet you see is no longer what the parser receives. When debugging, treat the payload like evidence at a scene: preserve bytes, hash samples, and compare normalized forms instead of eyeballing syntax highlighting.

Mistake 1—Trailing commas after the last property

Trailing commas are legal in modern JavaScript in many contexts. They are not legal in JSON.

{
  "userId": 42,
  "role": "editor",
}

That trailing comma after "editor" will break strict parsers. Some editors hide the issue because syntax highlighting still “looks fine.” Others auto‑format inconsistently depending on plugins.

Fix: Remove the comma—or configure your serializer (JSON.stringify) and avoid hand‑editing large blobs.

Where this bites hardest is generated configs: templating engines frequently emit trailing commas “because the last field changed.” Add a CI step that runs JSON.parse on every exported fixture.

Mistake 2—Using single quotes around strings

JSON requires double quotes for strings. Single quotes are invalid.

{
  'status': 'ok'
}

This is another JavaScript literal habit that leaks into configs and fixtures.

Fix: Replace single quotes with " and escape interior quotes as needed.

If you need programmatic repair during migration, a tiny serializer boundary helps—but prefer fixing at the source so humans stop learning the wrong muscle memory.

const repaired = JSON.stringify({ status: "ok" });

The snippet above is valid JavaScript that produces valid JSON text via JSON.stringify, which is the safest bridge when you are converting ad‑hoc literals into interchange format.

Mistake 3—Unescaped control characters inside strings

JSON strings cannot contain raw newlines. If you paste multi‑line text, you must encode line breaks as \n (or store base64, depending on your constraints).

Symptom: Errors mentioning “bad control character” or position offsets that point into the middle of a large string.

Fix: Serialize properly—don’t paste prose directly unless it’s escaped.

This mistake spikes when logs or stack traces get embedded into JSON manually. If you must embed arbitrary text, consider structured fields (message, details) and enforce escaping at the boundary rather than asking humans to “just paste it.”

Mistake 4—Hex literals, undefined, NaN, and Infinity

JSON supports null, booleans, numbers, strings, arrays, and objects—nothing else.

Developers sometimes emit:

  • undefined (drops silently in some serializers—or breaks others)
  • NaN / Infinity (not valid JSON tokens)

Fix: Map non‑JSON values explicitly (null, strings, or omit keys).

Observability payloads are notorious here: you stringify metrics objects containing NaN, and suddenly your exporter writes invalid JSON intermittently—only when a division by zero occurs.

Mistake 5—Duplicate keys: “valid-looking” but ambiguous

Some parsers accept duplicate keys; others reject them; consumers may pick first or last—behavior differs across stacks.

Example hazard:

{
  "retry": false,
  "retry": true
}

Even if parsing succeeds, downstream logic becomes nondeterministic.

Fix: Treat duplicates as a schema bug. Lint configs and enforce uniqueness.

If you rely on object spread in JavaScript, remember it resolves duplicates at the language level—but JSON parsing is not obligated to mimic that resolution policy across every runtime.

Mistake 6—Comments (// and /* */)

JSON has no comments. Yet “JSON with comments” appears everywhere because humans want annotations.

Fix: Use JSONC only where tooling explicitly supports it, or store metadata beside the payload.

Teams frequently rename files to .json while still containing comments, then wonder why production parsers reject them. Naming matters: call it .jsonc where allowed, or strip comments in a build step.

Mistake 7—Wrong encoding or BOM surprises

JSON is UTF‑8 in practice for web APIs. A misplaced BOM or mixed encodings can cause parsers to choke early—even when the text looks correct visually.

Fix: Normalize to UTF‑8 without BOM for interoperability; verify exports from Excel and legacy systems.

Windows‑originating files and certain database dumps inject invisible prefixes. If parsing fails at column zero with cryptic tokens, suspect encoding before rewriting structure.

Mistake 8—Megabytes of pretty‑printed JSON in hot paths

Not a syntax error—but an operational trap. Huge whitespace‑heavy payloads inflate bandwidth and obscure real bugs during diffing.

Fix: Minify for transport; pretty‑print only when humans need to read it.

Large formatted blobs also make code review painful: reviewers skim, missing a single stray comma introduced mid‑diff.

Mistake 9—Schema drift: types changing under your feet

A classic “soft” bug: userId flips from number to string across releases. Strict consumers break; loose consumers coerce dangerously.

Fix: Version your API contracts and validate at boundaries.

Soft drift often emerges from ORMs and serializers that “helpfully” stringify identifiers when formats collide.

Mistake 10—Logging secrets while debugging structure

You debug JSON by slicing objects—and accidentally paste tokens into tickets.

This is why local‑first tooling matters. Safe Local Tools is built around browser‑local processing: your content stays on your device during formatting and inspection workflows appropriate for development troubleshooting.

If your payload contains credentials, prefer offline iteration and aggressive redaction—even when you trust your collaborators—because retention policies rarely align with chat history.

A practical debugging workflow that actually finishes

When JSON fails, resist random edits. Use a tight loop:

  1. Capture the exact bytes that failed (not the reformatted version).
  2. Locate the error position reported by the parser.
  3. Shrink the payload with a binary search: remove halves until the minimal failing snippet appears.
  4. Validate against a schema if you have one (OpenAPI, JSON Schema).

If you paste redacted samples into Safe Local Tools, you can iterate quickly without spinning up a backend formatter.

Add one more habit: after fixing, re‑encode once through your production serializer. Many bugs live in double‑serialization layers—stringifying an already‑stringified value—rather than the visible text editor mistake.

Interoperability traps across languages and runtimes

JSON feels universal because every mainstream stack speaks it—but “parses JSON” is not a guarantee of identical semantics. Numbers are an enduring edge case: extremely large integers can lose precision in JavaScript’s number type even when the JSON text is technically valid. That nuance matters when identifiers or financial amounts cross language boundaries. Another trap is key ordering: JSON objects are unordered collections, yet humans rely on stable ordering for review and some consumers accidentally depend on insertion order. Finally, datetime strings introduce ambiguity unless you standardize on ISO‑8601 and explicit time zones. If you treat JSON as a contract, write down these decisions next to your schema so future refactors do not quietly reinterpret fields.

When you integrate third‑party SDKs, watch for “helpful” automatic deserialization that coerces types. It can mask malformed payloads until you hit a rare branch. A strict parse at the boundary—fail fast on unexpected shapes—often saves weeks later.

Keep a “golden sample” repository for payloads your system accepts today—tiny fixtures exercising nested arrays, unicode strings, and numeric extremes—then run them through parsing checks whenever dependencies upgrade. Pair those fixtures with minimal negative tests that intentionally include trailing commas and duplicate keys so regressions surface immediately before merge and noisy incidents quiet down for good at last.

Schema validation in CI

Add a step that validates exported JSON fixtures against JSON Schema or OpenAPI components. Syntax checks catch commas; schemas catch wrong field types before deploy.

Leading naturally into safer formatting

Once you know what breaks JSON, the remaining work is mechanical: normalize quotes, remove illegal tokens, validate structure, and compare before/after. Safe Local Tools gives you a fast loop for that—without shipping data off your machine.

When you’re ready to clean up a messy payload and confirm it parses cleanly, Try the JSON Formatter →