JSON Validation & Formatting: The Anatomy of Structured Data
JSON is the lingua franca of modern software: APIs speak it, configuration files are written in it, logs are shipped in it, and entire NoSQL databases store documents natively in it. Yet it is astonishingly easy to break — a single stray comma silences an integration, and a “smart quote” pasted from a word processor produces an afternoon of debugging. This guide dissects the format precisely, so you can read parser errors like sentences instead of runes.
The entire grammar, in six rules
JSON is defined by RFC 8259, and the grammar is small enough to hold in your head:
- A value is exactly one of: an object, an array, a string, a number,
true,false, ornull. Nothing else exists. - An object is an unordered set of
"key": valuepairs inside{ }. Keys are always strings — unquoted JavaScript-style keys are invalid. - An array is an ordered list of values inside
[ ], comma-separated, with no trailing comma. - A string is double-quoted Unicode with a fixed escape table (
\",\\,\/,\b,\f,\n,\r,\t,\uXXXX). Single quotes and literal control characters are forbidden. - A number is decimal with an optional exponent.
NaN,Infinity, hexadecimal and leading zeros are all invalid. - Whitespace (spaces, tabs, newlines) may appear between tokens — but never inside them. There are no comments.
Where validation actually fails
Real-world breakage clusters into a handful of recurring patterns. Recognising them by sight turns hours of hunting into seconds:
| Broken input | Why it fails | Typical parser message |
|---|---|---|
{"a": 1,} | Trailing comma before a closing brace | Unexpected token } |
{a: 1} | Key not quoted (valid JS, invalid JSON) | Unexpected token a |
{'a': 1} | Single-quoted string | Unexpected token ' |
[1, NaN] | NaN/Infinity are not JSON numbers | Unexpected token N |
{"a": "x–y"} with “smart quotes” | Typographic quotes from word processors are not ASCII " | Unexpected token in JSON |
File starts with { | UTF-8 BOM before the first token | Unexpected token ï |
{"a": 01} | Leading zero (Octal-looking literal) | Unexpected number |
Good validators go beyond “invalid” and report the exact line and column plus a human paraphrase — because position 4172 alone helps nobody.
Formatting vs minifying — and what re-serialisation really does
Both operations are the same two-step dance: parse the text into an in-memory tree, then emit it again with your chosen whitespace policy (2-space, 4-space, tab, or minified). But re-serialisation has side effects worth knowing:
- Key order is preserved as encountered in most engines — but keys that look like non-negative integers (
"3","42") get hoisted to the front of objects in JavaScript. Round-tripping can silently reorder them. - Numbers may not survive verbatim.
1.50comes back as1.5; very large integers lose precision beyond 2⁵³ (see below);1e999parses toInfinityand then serialises asnull. - Escapes are normalised.
\u0041becomesA; literal newlines inside strings remain illegal either way. - Duplicate keys collapse. Most parsers keep the last occurrence and discard the rest — a data-loss bug masquerading as tidiness.
9007199254740993 silently round to ...992. If your payloads carry 64-bit IDs, a serious validator should flag them — and you should parse them as strings or BigInt.JSON Schema in sixty seconds
Syntax validation proves the document parses. Schema validation proves it means something. A JSON Schema describes the shape your data must have:
{
"type": "object",
"required": ["id", "email"],
"properties": {
"id": { "type": "integer", "minimum": 1 },
"email": { "type": "string", "format": "email" },
"role": { "type": "string", "enum": ["admin", "member", "guest"] }
},
"additionalProperties": false
}
Against this schema, a syntactically perfect {"id": "abc"} still fails — the type is wrong. Schemas catch the class of bugs that unit tests usually discover in production: renamed fields, optional values that stopped being optional, enums that grew a new spelling.
Why validation belongs in your browser
Here is the uncomfortable part: JSON payloads are rarely innocuous. They contain API tokens, session cookies, customer records, internal hostnames, personal data. Paste such a payload into a random “free JSON formatter” website and you have transmitted confidential material to an unknown operator over an unencrypted-on-trust channel — many of those sites explicitly log inputs.
Validation is, mechanically, a pure function: bytes in, tree plus errors out. It needs no network, no GPU, no server of any kind. That is why json.clicktools.app parses, formats and schema-checks entirely in your tab — the same RFC 8259 grammar, executed locally, with zero possibility of your payload appearing in someone else's logs.
The takeaway
JSON's strength is its smallness: six grammar rules cover every document ever written. Learn the failure patterns, treat re-serialisation as a transformation (not a no-op), graduate from syntax checking to schemas as soon as money or identity touches the payload — and prefer validators that never see your data leave the building.
Next in the series: why 0.1 + 0.2 ≠ 0.3 — and what that means for unit converters.