How JSON.parse actually validates your JSON
The pretty-print button hides a strict spec. Here's what the browser really checks, why some errors are unhelpful, and how to read them anyway.
Control Plane Labs Staff
Published August 5, 2026
Every online JSON formatter — including the one at
/tools/json-formatter/ — is a thin wrapper around two
ECMAScript built-ins:
JSON.parse
and
JSON.stringify.
The pretty-printing is cosmetic. The interesting work is the parse — and the
parse follows a spec that is stricter than most people expect.
What “valid JSON” actually means
The current wire spec is RFC 8259, which supersedes RFC 7159 and 4627. Its grammar (§2) allows exactly:
- Objects — brace-delimited, keys must be double-quoted strings, values separated by commas, no trailing comma after the last pair.
- Arrays — bracket-delimited, same trailing-comma rule.
- Strings — double quotes only, backslash escapes,
\uXXXXfor BMP code points, surrogate pairs for anything above. - Numbers — IEEE 754 double-precision, no
+, no leading zero except0itself, exponents allowed. NotNaN. NotInfinity. Notundefined. - Booleans and
null— lowercase only.
Everything else is a syntax error. That includes several constructs that show up in JavaScript, YAML, and hand-edited config files every day:
{ foo: 1 }— unquoted key.{ "foo": 1, }— trailing comma.{ 'foo': 1 }— single quotes.// commentor/* comment */— no comments in JSON.NaN,Infinity,-Infinity,undefined— not JSON values.0123,.5,1.— malformed numbers.
Why the error messages are frustrating
JSON.parse throws a SyntaxError. The message format is not specified by
ECMAScript, so every JavaScript engine writes its own. Chrome (V8) is the most
informative — it prints the position and a snippet:
SyntaxError: Unexpected token 'a', "{ "name": alice }" is not valid JSON
at JSON.parse (<anonymous>)
Firefox (SpiderMonkey) gives a line and column:
SyntaxError: JSON.parse: expected double-quoted property name at line 1 column 12 of the JSON data
Safari (JavaScriptCore) is the terse one:
SyntaxError: JSON Parse error: Expected '"'
The tool renders whichever your browser produces — that’s the best signal available, because ECMA-262 §25.5.1.1 refuses to standardize the wording.
When the message is unhelpful (“Unexpected end of JSON input”), the trick is to bisect: cut the input in half, format each half, and the half that still errors contains the problem. Two or three bisections usually pinpoint it.
The four errors that account for most real inputs
1. Trailing commas from JavaScript source.
You copied { "foo": 1, } out of a .js file. JavaScript object literals
allow it since ES2017; JSON never has. Delete the comma.
2. Single quotes from a shell paste. The command line quoted the whole payload in double quotes, so the inner strings ended up in single quotes. Wrap once more with a JSON quote-fixing step, or paste the raw payload from your terminal’s captured output rather than the escaped one.
3. Unquoted keys from Python dict.__repr__ or YAML.
Python str(some_dict) produces {'a': 1} — that’s Python literal syntax,
not JSON. Use json.dumps on the Python side, or paste through a
YAML→JSON conversion (which happens to accept unquoted keys as YAML, then
emits valid JSON).
4. Comments.
Someone added // TODO to a config file. JSON forbids it; JSONC (used by
VS Code and TypeScript) permits it. The formatter treats input as strict
JSON. Strip the comments, or use a JSONC-aware tool.
Pretty-printing vs. re-serializing
The tool uses JSON.stringify(JSON.parse(input), null, indent). That means the
output is a new serialization, not a reformat of the input string. Two
consequences worth knowing:
- Key order is preserved for string keys and follows the object’s own insertion order (ECMAScript §7.3.23), which matches what every current engine ships. If you rely on key ordering, this is stable.
- Numeric precision is IEEE 754.
0.1 + 0.2becomes0.30000000000000004, and9999999999999999becomes10000000000000000. If your payload uses large integers or fixed-point decimals, use string encoding on the producer side.JSON.parsecannot round-trip a 64-bit integer through a JS number.
When JSON.parse is the wrong tool
- Streaming input —
JSON.parserequires the full payload in memory. For multi-GB inputs, use a streaming parser (clarinet,stream-json) instead of a formatter. - JSONL / ND-JSON — one JSON value per line. The formatter as written reads the whole textarea as a single value and will throw on the second brace. Split by newline first.
- Comments and trailing commas — use JSONC or JSON5. Both are supersets;
neither is what
JSON.parseaccepts.
FAQ
Frequently asked questions
Is my input sent to a server?+
Why does my file parse in VS Code but not here?+
Can I trust the output ordering?+
Why is my large integer being corrupted?+
Read next
- The JSON formatter tool itself.
- YAML ↔ JSON converter when the input is on the other side of the wire.
- The YAML + JSON reference for people who read config files all day.
Tags: #json, #rfc-8259, #web-dev