How to fix common JSON syntax errors
Nine causes ordered by how often they actually happen, plus why the reported line number is often not where the mistake is.
Almost every JSON parse error comes down to one of nine things. They are listed here roughly in the order they turn out to be the cause, so scanning from the top is the fastest route to a fix.
If you have the broken JSON in front of you, paste it into the JSON formatter first — it reports the exact line and column, which narrows most of what follows to a few seconds.
First: the position is where the parser gave up
This trips up more people than any single syntax rule. The line and column in an error message mark the point where the parser could no longer continue — not necessarily where you made the mistake.
{
"a": 1,
"b": 2
The fault is a missing }, which belongs on line 4. The error says line 4 column 1 — the end of the file. Here that happens to be close, but in a 500-line document a brace you forgot to close on line 12 is still reported at line 500. When the position looks like it points at perfectly good code, the real mistake is almost always earlier, and it is usually an unclosed bracket or quote.
1. Trailing comma
The most common by a wide margin.
{ "name": "Toolora", "free": true, }
{ "name": "Toolora", "free": true }
JavaScript allows a trailing comma in object and array literals, so editors and habit both push you toward one. JSON does not allow it anywhere. If you are hand-editing config, this is the first thing to check.
Note the two errors read differently. A trailing comma in an object gives you a position; in an array, V8 reports Unexpected token ']' with no position at all. That is a quirk of the engine, not a sign of a different problem.
2. Single quotes, or unquoted keys
{ 'name': 'Toolora' }
{ "name": "Toolora" }
JSON requires double quotes, on keys and on string values alike. Single quotes are never valid. Unquoted keys — fine in JavaScript, where {name: "x"} is normal — are also rejected.
Both produce the same message: Expected property name or '}'.
3. Comments
JSON has no comment syntax. Neither of these is valid:
{
// the display name
"name": "Toolora"
}
{ /* the display name */ "name": "Toolora" }
This surprises people because so many tools do accept comments in files named .json. Those tools implement JSONC or JSON5, which are separate formats — VS Code’s settings.json and tsconfig.json are the usual culprits. A strict parser will reject the same file.
If you need to annotate JSON that a strict parser will read, put the note in a real key:
{ "_comment": "display name", "name": "Toolora" }
4. NaN, Infinity and undefined
None of them exist in JSON. null is the only empty value the format has.
{ "score": NaN, "limit": Infinity, "note": undefined }
{ "score": null, "limit": null, "note": null }
This usually arrives from JSON.stringify output that was assembled by hand, or from a language whose float type has an infinity value. Decide what each one should mean — null, 0, or omitting the key entirely — before serialising.
5. Unescaped characters inside strings
A JSON string cannot contain a raw newline, a raw tab, an unescaped ", or a lone \.
{ "path": "C:\Users\me" }
{ "path": "C:\\Users\\me" }
Windows paths are the classic case: every backslash needs doubling. A raw newline reports Bad control character in string literal; a stray backslash reports Bad escaped character. Both point at the offending character, so these two are easy to fix once you know the message.
Multi-line text needs \n, not an actual line break:
{ "note": "line one\nline two" }
6. Wrong or unbalanced brackets
{ "items": [1, 2, 3} }
{ "items": [1, 2, 3] }
Objects close with }, arrays with ]. Mixing them, or losing count in nested data, produces an error whose position — per the rule at the top — may be a long way from the mistake. Formatting the document is the quickest way to see the structure: indentation makes an unbalanced level obvious at a glance.
7. An invisible character at the start
An error on the very first character of a file that looks completely correct usually means a byte order mark — an invisible U+FEFF that some Windows editors write at the start of UTF-8 files, and that survives copy-paste from certain sources.
Your editor will show nothing. The parser reports Unexpected token. Save the file as “UTF-8 without BOM”, or retype the opening brace.
The same applies to non-breaking spaces and other invisible characters pasted in from a web page or a document.
8. Numbers too large to survive the round trip
This one does not throw an error, which makes it the most dangerous on the list.
JavaScript numbers are IEEE-754 doubles, so integers above 9,007,199,254,740,991 (Number.MAX_SAFE_INTEGER) cannot be represented exactly. JSON.parse accepts them and quietly returns something else:
{ "id": 1234567890123456789 }
Parsed and re-serialised in JavaScript, that becomes 1234567890123456800. The ID is now wrong, no error was raised, and nothing in your logs will say so.
Large IDs — Discord snowflakes, Twitter/X IDs, database bigints — should travel as strings:
{ "id": "1234567890123456789" }
If you control the API, this is worth fixing at the source rather than in every consumer.
9. Key order is not guaranteed
The JSON specification defines an object as an unordered set of name/value pairs. In practice most parsers preserve the order you wrote — but not always, and JavaScript has a specific exception worth knowing.
Keys that look like non-negative integers are reordered numerically and moved to the front:
{ "b": 1, "a": 2, "2": 3, "1": 4 }
Round-tripped through JSON.parse and JSON.stringify, that comes back as {"1":4,"2":3,"b":1,"a":2}. This is a rule of JavaScript objects, not of the parser, and it applies to every object with integer-like keys.
If order matters — a sequence of steps, a ranked list — use an array. That is what arrays are for, and their order is guaranteed.
Fixing it
Paste the document into the JSON formatter. It reports the line and column of the fault, and formatting valid JSON with consistent indentation makes structural problems visible immediately. Everything runs in your browser, so config files with credentials in them never leave your machine.