Your JSON isn't broken — your strings are: escapes, BOMs and the 2^53 lie
A few weeks ago we published a 30-second audit for spotting JSON tools that leak your payloads. This post is about the other kind of pain: the times JSON "breaks" and it's not the JSON's fault at all — it's the strings,
A few weeks ago we published a 30-second audit for spotting JSON tools that leak your payloads. This post is about the other kind of pain: the times JSON "breaks" and it's not the JSON's fault at all — it's the strings, the invisible characters, or a number that silently lied to you.
These are the four failure modes we see most, and what to actually do about them.
1. There are only eight legal escapes — everything else is a landmine
JSON strings allow exactly: \" \ \/ \b \f \n \r \t and \uXXXX. That's it.
Two gotchas hide in plain sight:
-
Astral characters need surrogate pairs.
\uXXXXis one UTF-16 code unit. To escape 𝄞 (U+1D11E) you need\uD834\uDD1E. A lone surrogate like\uD834is invalid JSON — yet some parsers accept it and crash later, far from the cause. - Real newlines and tabs are illegal inside strings. Pasting a literal tab from a terminal output, or a multi-line string from a code editor, breaks strict parsers with a confusing "Unexpected token".
Test escapes round-trip instead of eyeballing: the JSON escape tool has a minimal mode and an ASCII-safe \uXXXX mode, and the unescape tool validates what comes out instead of silently returning garbage.
2. The invisible characters: BOM, U+00A0, and friends
A file that looks perfectly fine in your editor but fails with Unexpected token is almost always a UTF-8 BOM. The spec (RFC 8259) says producers must not add one — and explicitly lets parsers ignore it. Plenty of parsers don't.
Similarly, content copied from PDFs or Word documents picks up typographic quotes, en-dashes and non-breaking spaces (\u00A0) that are invisible in most editors but structurally fatal. A tree viewer that can display raw escapes makes these obvious in seconds — our JSON viewer does exactly that, and it all runs in your browser.
3. The 2^53 lie: when parsing silently changes your data
This is the nastiest one because there's no error.
JavaScript numbers are IEEE-754 doubles, so any integer above 2^53 - 1 (9007199254740991) can't be represented exactly. Parse 9007199254740993 with JSON.parse and you silently get 9007199254740992. No exception. No warning.
Where this bites in real life:
- Snowflake IDs (Twitter, Discord) — deliberately generated above 2^53
- Payment/transaction IDs from payment providers
- Millisecond timestamps far into the future (rare, but possible)
The fix is boring but non-negotiable: big IDs travel as strings. If you're auditing an existing integration, paste a real response into a strict validator — ours flags lossy integers before they reach your code.
4. JSON-in-JSON: the double-escape onion
The most confusing sight in a log: a value that looks like "{\"a\": 1}". That's a JSON document serialized as a string inside another JSON document — logs, webhooks and message queues do this constantly.
Strip one level of escaping, then parse again. For real payloads use something like fromjson in jq running in your browser — no terminal, no uploads, described in our post on client-side jq.
Why we care so much about this
Every tool linked above is 100% client-side: paste your payload, and nothing leaves your browser tab. After the CodeBeautify leak (user-pasted payloads exposed through a public feed), "the tool never sees your data" stopped being a nice-to-have for us — it's the product. The full story is in the leak explained.
If you want the reference version of all of this — the full escape table, the JSON vs JSON5 vs JSONC vs NDJSON comparison, and the base64 alphabet traps — we put together a one-page cheat sheet you can keep open next to your editor.
What's the weirdest JSON failure you've debugged? Wrong-position Unexpected token stories especially welcome.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.