JSON is the most-read data format in the working programmer's day — API responses, config files, package manifests, log lines. It's also deceptively strict: the syntax fits on an index card, yet malformed JSON remains one of the most common causes of broken builds and failed API calls. This guide covers the entire format and, more usefully, the specific mistakes that cause almost all real-world parse errors.

The whole format in five rules

  1. A JSON document is one value: an object {}, array [], string, number, true, false, or null.
  2. Objects are unordered key–value pairs. Keys must be strings in double quotes: {"name": "Ada"}.
  3. Arrays are ordered lists of any values: [1, "two", {"three": 3}, null].
  4. Strings use double quotes only, with backslash escapes: \", \\, \n, \t, and A-style unicode.
  5. Numbers are decimal only — no leading zeros (01 is invalid), no NaN, no Infinity, no hex.

Everything JSON cannot do is implied by that list, and it's worth knowing explicitly: no comments, no trailing commas, no single quotes, no unquoted keys, no undefined, no dates (dates travel as strings, by convention ISO 8601 like "2026-07-08T10:00:00Z").

The errors that cause 90% of parse failures

The trailing comma

{
  "name": "Ada",
  "role": "engineer",   ← this comma is fatal
}

Legal in JavaScript objects, illegal in JSON. This single difference is probably the most common JSON error in existence, because developers write JSON with JavaScript muscle memory. Typical parser message: Unexpected token } — note that the parser points at the brace, one character after the actual problem. Parser errors generally point at where the text stopped making sense, which is at or shortly after the real mistake.

Single quotes and unquoted keys

{ name: 'Ada' }        ← two errors: unquoted key, single quotes
{ "name": "Ada" }      ← valid

Again valid JavaScript, invalid JSON. Config files hand-written by developers are the usual source.

Comments

JSON has no comment syntax — a deliberate design decision by Douglas Crockford to prevent comments being abused as parsing directives. If you control the format and need comments, the pragmatic options are a dedicated "_comment" key, or using JSON5/JSONC formats where your tooling supports them (VS Code's settings files, for example, are JSONC, which is why comments work there and break the moment you paste the same content into a strict parser).

Invisible characters

The nastiest category, because the JSON looks perfect:

  • Smart quotes (“ ” instead of " ") — arrive via copy-paste from Word, Google Docs, Slack, or a blog post. The parser fails on what your eye reads as a normal quote.
  • A UTF-8 BOM — three invisible bytes some Windows editors prepend to files. Strict parsers reject the document at position 0.
  • Non-breaking spaces where regular spaces should be — same copy-paste sources.

If a parse error makes no visual sense, suspect invisible characters first and retype the offending line by hand.

Double-encoded JSON

{"data": "{\"user\":\"ada\",\"id\":42}"}

If you see \" everywhere, a system serialized JSON, then serialized the result again as a string. You'll need to parse twice to get at the data — and somewhere upstream, a producer is calling stringify one time too many. This is a bug worth fixing at the source rather than working around, because double-encoding compounds every time the data passes through the buggy layer.

A debugging workflow that finds errors fast

  1. Run it through a validator — our JSON formatter parses entirely in your browser (safe for API payloads containing real data, since nothing is uploaded) and reports the line and column of the first error.
  2. Look at and immediately before the reported position — remember the parser reports where text stopped making sense, and the true mistake is usually just before that point.
  3. Pretty-print early. A missing bracket in minified JSON is almost impossible to spot; in indented JSON the structure error is often visible at a glance.
  4. For large documents, bisect: delete half the document (keeping it structurally closed), re-validate, and repeat on whichever half still fails. Ten rounds of this finds one bad line in a thousand.

Three habits that prevent the problems

  • Never build JSON by string concatenation. Every language ships a serializer (JSON.stringify, json.dumps, PHP's json_encode) that handles quoting and escaping correctly. Hand-built JSON works until the first value containing a quote character, and then it fails in production.
  • Always check the parse result. In PHP, json_decode returns null on failure — indistinguishable from parsing the valid document null — unless you use the JSON_THROW_ON_ERROR flag, which you should.
  • Mind number precision across languages. JavaScript stores all numbers as 64-bit floats, so integers beyond 253 silently lose precision — the classic symptom is 64-bit database IDs ending in 00 after a round-trip through a JS client. APIs that use large IDs (Twitter's, famously) send them as strings for exactly this reason.

JSON earned its ubiquity by being small enough to learn in an afternoon. The strictness that causes these paper cuts is the same property that makes it reliable: there's exactly one way to write valid JSON, which means a document that parses on your machine parses everywhere.