The whole grammar, standardised as RFC 8259 and ECMA-404, permits exactly six kinds of value: object, array, string, number, boolean and null. Keys must be strings in double quotes. That is the entire specification, and almost every error people hit comes from assuming something else is allowed.
| What people write | Why it fails |
|---|---|
| A key without quotes | Keys must be quoted strings, always |
| A string in single quotes | Only double quotes are strings in JSON |
| A comma after the last item | Trailing commas are not permitted |
| A comment on its own line | JSON has no comments at all |
| NaN, Infinity or undefined | None of these are JSON values |
| A date | There is no date type — dates are strings by convention |
| Wrapping the whole thing in a function call | That is JSONP, not JSON |
This fragment contains three separate errors, and most editors report only the first:
{ id: 1, name: two, tags: [a, b,] }
| Position | Problem | Fix |
|---|---|---|
| The keys | Unquoted identifiers | Quote every key |
| The values | Bare words are not strings | Quote every string value |
| After the last array item | Trailing comma | Remove it |
The reason errors cascade like this is that a parser fails at the first byte it cannot account for and reports a character offset, not a diagnosis. A message about an unexpected token at position 2 usually means the problem started earlier — a quote you closed too soon, or an opening brace with no partner.
Two error messages worth recognising on sight. An unexpected token at position 0 often means the file begins with a UTF-8 byte order mark, an invisible three-byte prefix that some Windows editors add; the JSON is otherwise perfect and looks it. And an unexpected end of input means a bracket or brace was never closed, which formatting will locate immediately once the rest parses.
This one silently corrupts data, and it is the most consequential item on the page. JSON numbers have no size limit in the specification, but JavaScript parses every number as a double-precision float. Integers stay exact only up to 2 to the 53rd power minus one, which is 9,007,199,254,740,991.
| Value in the JSON text | Value after parsing in JavaScript |
|---|---|
| 9007199254740992 | 9007199254740992 |
| 9007199254740993 | 9007199254740992 — changed |
| 0.1 plus 0.2 | 0.30000000000000004 |
No error is raised. The number simply comes out different. This is why large-scale APIs that use 64-bit identifiers also send a string version of the same field — the numeric one cannot survive a round trip through a JavaScript client. If you are designing an API, send identifiers, currency amounts and anything else that must be exact as strings, and parse them deliberately.
The specification does not say what should happen when the same key appears twice in one object. In practice most parsers keep the last occurrence, some keep the first, and a few raise an error.
That ambiguity has a security consequence. If a request passes through two components that use different parsers — a gateway that validates and a service that acts — and each resolves duplicates differently, then one document can mean two things. A validator sees the harmless first value while the service acts on the second. The defence is to reject duplicate keys outright rather than to pick a winner.
A related class of bug: a key of __proto__ in JSON is a harmless string as far as parsing goes, but if the parsed object is then merged into an existing object with a naive deep-merge routine, it can alter the prototype chain and change behaviour across an entire application. This is prototype pollution, and it is a real vulnerability class rather than a curiosity. Parsing is safe; careless merging afterwards is not.
JSON strings are sequences of Unicode characters, with escape forms for the double quote, the backslash itself, newline, tab, carriage return, form feed, backspace, and a four-hex-digit numeric form. Characters outside the basic multilingual plane — most emoji, many historic scripts — need two of those numeric escapes forming a surrogate pair. A single unpaired half is technically invalid, and parsers differ on whether they reject it or pass it through as a damaged character, which is a common cause of text that looks fine in one system and broken in the next.
The encoding itself should always be UTF-8. The specification permits it exclusively for data exchanged between systems, so a file in a legacy single-byte encoding will parse but produce mangled non-ASCII text.
| Format | Adds | Where you meet it |
|---|---|---|
| JSONC | Comments | Editor and compiler config files |
| JSON5 | Comments, trailing commas, unquoted keys, single quotes | Human-edited configuration |
| JSON Lines | One JSON value per line, no enclosing array | Logs and streaming pipelines |
This is why a configuration file ending in .json that is full of comments is not valid JSON and will be rejected by a strict validator, even though the tool that owns it reads it happily. If a formatter refuses your config, check whether the file is actually JSONC before assuming the file is broken.
A formatter checks syntax, not meaning. Valid JSON can still be wrong for its purpose: a missing required field, a string where a number was expected, an enumerated value outside the allowed set. Catching those requires a schema — JSON Schema is the usual tool — and no beautifier can substitute for it.
Formatting also does not change your data, and that includes key order. Order carries no meaning in a JSON object as far as the specification goes, but version-control diffs and checksums care very much, so a reformat that reorders keys will produce a large and misleading diff.
Practical constraints: very large documents will freeze a browser tab, because the whole structure must be held in memory at once alongside the formatted output; deeply nested structures can exhaust the parser stack; and streaming formats such as JSON Lines must be split by line before each record is parsed.
One security habit worth keeping regardless of any privacy claim: avoid pasting production credentials, tokens or personal data into any web tool as a matter of routine. This page processes text in your browser and sends nothing, and you can confirm that yourself by watching the network panel in developer tools — but the general practice of not circulating live secrets through utilities is the stronger protection.
Comments or trailing commas, almost always. Your editor is reading it as JSONC; a validator is reading it as JSON.
Floating-point rounding above 2 to the 53rd. Ask for the identifier as a string, or parse it with a big-integer aware reviver.
No. Only whitespace changes. If a value looks different afterwards, the parser altered it — which points to the number precision issue above.
No. Parsing, validation and formatting all happen in your browser, and nothing you paste is transmitted, logged or stored.
Every tool comes with a written guide, and every category is one click away.