Uvlio

Command Palette

Search for a command to run...

Back to articles
Technical Article

Why Valid JSON Breaks: Commas, Numbers, and Escapes

JSON looks forgiving because it looks like JavaScript. It is not. The grammar is small and deliberately rigid, and most of the time a payload fails for one of a handful of reasons that a good error message points at directly. The harder problems are the ones that parse cleanly and are still wrong.
Uvlio editorial team by limitcool2026-05-177 min read
Topic coverDeveloperJSONPretty Print

Why Valid JSON Breaks: Commas, Numbers, and Escapes

JSON is stricter than it looks. What a parser error position really tells you, why long IDs change value, and what a formatter can never catch.

Guide subject preview
{"name":"Ava","roles":["admin"]}
format before review
validate structure first
Tool stack
JSON FormatterText Cleaner
Reading focus
1Understand
2Check
3Apply

Original workflow visual

Why Valid JSON Breaks: Commas, Numbers, and Escapes

This original Uvlio visual summarizes the practical path from input inspection to output review for this workflow.
1

Understand

Review before moving forward

2

Check

Review before moving forward

3

Apply

Review before moving forward

Maintainer and review note
Maintained by limitcool. Use it to understand the technical model, processing boundaries, privacy risks, and verifiable behavior.
The grammar is smaller than people expect

Four things that are legal in JavaScript are illegal in JSON: a trailing comma after the last element, single-quoted strings, unquoted object keys, and comments. NaN and Infinity are not valid numbers either, and neither is a leading plus or a leading zero. Most hand-edited JSON fails on exactly one of these. If a config file was written by a person rather than a program, check the last element of every array and object first — the trailing comma is by far the most common single cause.

Read the error position, not just the message

A parser reports the offset where it gave up, which is usually just after the real mistake rather than on it. An unterminated string is reported at the end of the file, because the parser kept consuming characters looking for a closing quote. An unexpected token at line 40 often means a comma is missing at line 39. Format the document first: once the structure is indented, the eye finds the unbalanced brace far faster than by counting characters.

Numbers are where data quietly disappears

JSON does not define a numeric precision, so nearly every parser reads numbers into an IEEE-754 double. That holds integers exactly up to 2^53, about 9.007 quadrillion. A 19-digit Twitter-style ID or a Snowflake ID exceeds that, so it is silently rounded and the last digits change. The payload stays valid and the value is now wrong. Any identifier that will not fit in 53 bits should be transported as a string, and the same applies to money if you are storing minor units in a large integer.

Duplicate keys resolve differently everywhere

The specification does not say what happens when an object contains the same key twice. Most parsers keep the last occurrence, some keep the first, and a few raise an error. This matters when payloads are assembled by string concatenation or merged from templates, because the duplicate is invisible in the rendered output. Key order has the same ambiguity: objects are unordered by definition, so sorting keys is useful for comparing two payloads but must never be relied on for meaning.

Escapes and Unicode

Inside a string, a backslash, a double quote, and control characters below U+0020 must be escaped. The \uXXXX form encodes one UTF-16 code unit, which means characters outside the Basic Multilingual Plane — emoji, rarer CJK characters — need a surrogate pair of two escapes. A lone surrogate is technically malformed and will produce a replacement character somewhere downstream. If Chinese or Japanese text arrives as question marks or boxes, the encoding broke before JSON was involved; the payload is a symptom, not the cause.

Minify and format solve different problems

Formatting is for humans reading a payload; minifying is for bytes on the wire. The saving from minifying is smaller than it looks once transport compression is on, because gzip and brotli handle repeated whitespace efficiently. Minify at the point of sending, keep the formatted version in source control, and never store a minified payload as the file a person is expected to edit.

What a formatter cannot tell you

A formatter answers one question: is this well-formed JSON. It cannot tell you whether a required field is missing, whether a string should have been a number, or whether an empty array means "none" or "not loaded". Those are schema questions. A payload that formats perfectly can still be rejected by the API you are sending it to, so treat a successful format as the beginning of debugging rather than the end.

Common Questions

Why does a trailing comma break my JSON?

The grammar has no production for it. JavaScript tolerates it, JSON does not, and it is the single most common cause of a hand-edited file failing to parse.

Why did my long ID change value after a round trip?

It was parsed into a double. Integers above 2^53 cannot be represented exactly, so the low digits are rounded. Send identifiers of that size as strings.

Can I put comments in a JSON file?

Not in standard JSON. Some tools accept JSON5 or JSONC, but anything sent over an API should assume comments are a parse error. A dedicated "_comment" key is the usual workaround.

Should I minify before sending a request?

Only if you are not already using transport compression. Gzip removes most of the cost of pretty-printing, so readability is usually the better trade.