Why is my JSON invalid? — common syntax errors and how to fix them
On this page
Your JSON looks fine. The parser disagrees.
Most “invalid JSON” is not a mystery. It is a JavaScript object, a Python dict, or a VS Code settings file wearing JSON’s clothes. Strict JSON — RFC 8259 — rejects trailing commas, single quotes, comments, unquoted keys, and a handful of number shapes every neighboring language accepts.
This page is the short list of those rules, with before/after fixes. Paste the broken text into the validator to jump to the error. Pretty-print the result in the formatter. Both run in your browser. Nothing is uploaded. There is no account.
JSON’s strict rules in one screen
JSON is six value types and a small set of punctuation. That is the entire language.
| Rule | Allowed | Rejected |
|---|---|---|
| Strings and keys | Double quotes "name" | 'name', unquoted name |
| Trailing commas | No | { "a": 1, } and [1, 2,] |
| Comments | No | //, /* */, # |
| Numbers | -12, 3.14, 1.5e10 | 012, 1., .5, NaN, Infinity |
| Extra values | true, false, null | undefined, None, Nil |
| Root | Any single JSON value | Two values side by side, or a whole NDJSON file as one document |
An object is { ... }. An array is [ ... ]. A document is exactly one value. Keys are always strings. Whitespace between tokens is fine; a raw newline inside a string is not.
If you remember one thing: JSON is not JavaScript. JSON.parse is stricter than an object literal. The same is true of Python’s json.loads versus a dict you typed in a REPL. For the six types and the rest of the gotchas, see What is JSON?.
Trailing commas, single quotes, comments
These three cause most of the red status lines. They are legal in neighboring formats. They are not legal here.
Trailing comma. Easy to leave when you delete the last item, or when a JavaScript pretty-printer adds one.
Before:
{
"name": "Ada",
"role": "admin",
}
After:
{
"name": "Ada",
"role": "admin"
}
Same rule in arrays: [1, 2, 3,] is invalid. Drop the last comma. JSONC and JSON5 allow trailing commas; strict JSON does not. The validator will usually say Unexpected token } or Unexpected token ] at the comma’s neighbor.
Single quotes. Python prints dicts with single quotes. JavaScript accepts them in source. JSON does not.
Before:
{ 'name': 'Ada', 'ok': true }
After:
{ "name": "Ada", "ok": true }
If the string itself contains a double quote, escape it (\") — do not switch the outer quotes to single.
Comments. tsconfig.json and VS Code settings are JSONC. Real JSON has no comment syntax.
Before:
{
// production host
"host": "api.example.com"
}
After:
{
"host": "api.example.com"
}
Move the note to a "_comment" field if you must keep it in-band, or keep a sidecar README. Do not ship // to a strict parser.
Unescaped strings and bad numbers
Once quotes and commas are clean, the next failures are almost always a string that was not escaped, or a number JSON does not have.
Quotes and backslashes inside strings. A raw " ends the string. A single \ starts an escape; if the next character is not a valid escape, the parse dies.
Before:
{ "path": "C:\temp\new", "note": "She said "ship it"" }
After:
{ "path": "C:\\temp\\new", "note": "She said \"ship it\"" }
Windows paths are the classic trap: \t is a tab and \n is a newline. Double every backslash, or use forward slashes. Newlines inside a string must be written \n, not as an actual line break. Bare keys ({ name: "Ada" }) fail the same way as single quotes — quote them.
Bad numbers. JSON numbers cannot have a leading zero (except 0 itself), a trailing decimal point, or a leading decimal point. They cannot be NaN or Infinity.
Before:
{ "zip": 02115, "score": NaN, "ratio": .5 }
After:
{ "zip": "02115", "score": null, "ratio": 0.5 }
Keep leading-zero IDs as strings. Encode missing math as null (or a documented sentinel string), not NaN.
Using the validator to find the line
You do not have to hunt by eye.
- Open the JSON validator.
- Paste the document. The status line under the editor is the answer:
✓ Valid JSONor✗ Invalid JSONplus the browser’sJSON.parsemessage. - Read the position. Messages look like
Unexpected token } in JSON at position 47orExpected double-quoted property name. The number is a character offset from the start of the paste, not always a line number. Jump there in any editor, or count from the top of a short snippet. - Fix that token. Paste again. Repeat until the status is green.
- When it is valid, send the same text through the formatter if you want indentation you can read.
Typical mappings:
| Status line | Fix |
|---|---|
Unexpected token } / ] | Trailing comma |
Expected double-quoted property name | Single-quoted or bare key |
Unterminated string | Missing quote, or a raw newline in a string |
Unexpected number | Leading zero |
Unexpected end of JSON input | Missing } or ] |
Unexpected non-whitespace character | A second value after the first, or a comment |
The paste never leaves your machine. The page uses the browser’s own JSON.parse. Open DevTools → Network if you want to confirm there is no upload. No signup.
Format vs minify vs validate — which tool when
Same engine, three jobs.
| You want | Use |
|---|---|
| Is this parseable, and where does it break? | Validator |
| Readable indent, sorted keys, a copy button | Formatter |
Smallest valid JSON for a URL, log line, or data-* attribute | Minifier |
| A YAML file humans will edit | JSON → YAML |
Validate first. Formatting and minifying both call JSON.parse and then JSON.stringify — they cannot pretty-print a document that is not JSON yet. If the formatter’s status is red, you are still in the syntax-error loop above.
Once it is valid:
- Format when you will read or diff it. Two-space indent is the usual default; tick Sort keys if you want a stable, git-friendly order.
- Minify when the consumer does not care about whitespace. If the response is already gzipped, the extra savings are small. Minify still wins for inline JSON.
- Validate when you only need a yes/no and a position — fixtures, a webhook body, a blob someone pasted into Slack.
None of these tools check a schema. “Valid JSON” means the text parses. It does not mean the object has the fields your API promised. For that you want JSON Schema or a runtime checker in your language.
If the file is meant for humans to edit — comments, less punctuation — JSON may be the wrong format. See JSON vs YAML.