Trailing commas, single quotes, comments — the five mistakes that account for most "but it looks fine" JSON failures, and the one-character fix for each.

JSON looks simple — until your parser throws SyntaxError: Unexpected token at line 47 of a 200-line config file and you can't see what's wrong. The spec (RFC 8259) is barely sixteen pages, but small differences from JavaScript's looser object syntax catch out experienced developers all the time. The fix is usually one character.

Here are the five errors that account for the vast majority of "but it looks fine" JSON failures — what the parser sees, why it complains, and how to spot the same shape next time. If you want to throw a blob into a working tool while you read, our JSON formatter will point at the exact offending column.

1. Trailing commas

JavaScript object literals tolerate them. JSON does not.

{"name": "ada",}   ✗ trailing comma — invalid JSON
{"name": "ada"}    ✓ valid

[1, 2, 3,]         ✗ trailing comma — invalid
[1, 2, 3]          ✓ valid

The grammar in RFC 8259 defines an object as { member, member, member } — commas are separators between members, not terminators. The same rule applies to arrays.

This usually bites when you're hand-editing config files: you delete the last entry, forget the comma that was on the previous line, save, and the parser stops cooperating. Some tooling has trained us in the opposite direction — ESLint will helpfully add trailing commas to JS source so diffs are cleaner, and that habit carries over.

If your build chain includes a JSON5 or JSONC file (VS Code's settings.json is JSONC), trailing commas are allowed there — but they will fail the moment that file is read by a strict parser, like an HTTP client or a Go encoding/json call.

2. Single vs double quotes

JSON requires double quotes around every string. Single quotes are rejected, even though JavaScript treats 'foo' and "foo" as equivalent.

{'name': 'ada'}    ✗ single quotes — invalid
{"name": "ada"}    ✓ valid

This goes for keys as well as values. The reason is that JSON is a strict subset of JavaScript object notation — the spec authors chose one quote style and one only to keep parsers simple and avoid the edge case of escaped quotes within mixed-quote strings.

If you're generating JSON from a templating language (Jinja, Mustache, Handlebars) and getting single quotes by mistake, check whether you're using raw string interpolation or Python's repr() — both prefer single quotes by default and will silently emit invalid JSON. Use json.dumps() in Python, JSON.stringify() in JavaScript, or the equivalent in your language to serialize properly.

3. Unquoted keys

JavaScript object literals let you write keys without quotes — {name: "ada"} — when the key is a valid identifier. JSON requires every key to be a quoted string, no exceptions.

{name: "ada"}      ✗ unquoted key — invalid
{"name": "ada"}    ✓ valid

You'll hit this when copy-pasting from JS source into a .json file or when a colleague writes documentation showing "the object" without actually meaning JSON. It's also a sign of confusion when a YAML or TOML user is writing JSON for the first time — both of those allow bare keys.

A related trap: numeric keys. JSON keys are always strings, even if the value looks like a number.

{1: "first"}       ✗ unquoted, numeric — invalid
{"1": "first"}     ✓ valid

If you're querying nested data and not sure how a parser will interpret your structure, JSON Path lets you test selectors against a real JSON blob.

4. Comments

JSON has no comments. Not //, not /* */, not #. Douglas Crockford (the spec's designer) deliberately left them out — his reasoning was that comments encouraged people to embed parsing directives, defeating the point of a portable data format.

{
  // user record   ✗ JSON has no comments
  "name": "ada"
}

Most parsers will reject the entire document if they encounter a comment-shaped token. Some lenient parsers (jq, JSON5, JSONC) accept comments — but anything that hits a stricter parser downstream will fail.

The pragmatic workaround is to add a "_comment" field with the note as its value. Parsers that don't recognize it will ignore it, and humans editing the file get the context.

{
  "_comment": "user record — see PR #423",
  "name": "ada"
}

If you're copying JSON from JS or Python source that includes inline notes, strip them first.

5. Special characters in strings

Strings in JSON must escape four kinds of characters: the double quote (\"), the backslash (\\), control characters below U+0020 such as \n and \t, and the forward slash (\/) if you want — the last one is optional but useful in HTML contexts.

{"path": "C:\Users\ada"}            ✗ backslash not escaped
{"path": "C:\\Users\\ada"}          ✓ valid

{"quote": "She said "hi""}          ✗ unescaped quote
{"quote": "She said \"hi\""}        ✓ valid

{"note": "line one
line two"}                          ✗ literal newline
{"note": "line one\nline two"}      ✓ valid

For arbitrary Unicode, JSON strings support \uXXXX escapes — useful when you can't trust the encoding of the channel transporting the payload.

From the spec

"All Unicode characters may be placed within the quotation marks, except for the characters that MUST be escaped: quotation mark, reverse solidus, and the control characters (U+0000 through U+001F)."

RFC 8259 §7 (IETF, public domain)

That sentence is the entire rule for what counts as a valid JSON string. Memorize it and §5 (the trailing-comma rule) and you've covered the four most common parse failures.

It's also the reason pasting JSON between systems with mismatched line endings (Windows CRLF vs. Unix LF) sometimes breaks silently. If you need to compare two payloads that should be equivalent but one parser rejects, JSON diff will show you the exact byte that differs.

The Toolhub workflow

Three browser-side tools cover most JSON-debugging cases:

Everything runs locally — your JSON never leaves the tab. Bookmark whichever fits the way you debug.

← All articles