Why JSON error messages mislead you
JSON parsers are not designed to give you friendly error messages. They are designed to be fast and correct. When they encounter something unexpected, they report the position where they realized something was wrong — which is almost never the position where the author made a mistake. A trailing comma at line 12 might not be detected until the parser reaches the closing brace at line 87, because until that point the parser was still hoping the document would become valid.
The canonical JavaScript error — SyntaxError: Unexpected token '}' — tells you almost nothing. The closing brace (}) is not the problem. Whatever came before it left the parser in a state where a closing brace was not a valid next token. You need to work backward from the error position, not forward from it.
The most common JSON mistakes and where they hide
These are the mistakes that account for the overwhelming majority of JSON parse failures:
Trailing commas. The most common. JSON does not allow a comma after the last element in an array or the last property in an object. This is legal in JavaScript (ES5+) and in many programming languages, which is why developers write it instinctively. Every JSON linter catches it; no JSON parser tolerates it.
// INVALID — trailing comma after last property
{
"name": "Alice",
"role": "admin", // <-- this comma is the problem
}
// INVALID — trailing comma in array
["red", "green", "blue",]Single quotes. JSON strings must use double quotes. Single-quoted strings are a JavaScript convention that the JSON spec explicitly excludes. This catches people who hand-write JSON after spending the day writing JavaScript.
// INVALID
{ 'name': 'Alice' }
// VALID
{ "name": "Alice" }Unescaped special characters in strings. Quotation marks inside a string value must be escaped as \". Backslashes must be escaped as \\. Control characters (newlines, tabs) must use their escape sequences (\n, \t), not literal characters. Literal newlines inside strings are not valid JSON.
Comments. JSON has no comment syntax. None. Not //, not /* */, not #. Douglas Crockford intentionally removed comment support from JSON because comments in data interchange formats were being abused to carry parsing directives. The strictness was deliberate. If you need comments, use JSONC or JSON5 — but run them through a preprocessor before passing the output to a standard JSON parser.
NaN and Infinity. JSON has no special numeric literals. NaN, Infinity, and -Infinity are not valid JSON values. This catches developers who serialize JavaScript floating-point results directly — division by zero produces Infinity in JavaScript, which JSON.stringify converts to null silently, which the receiver then parses as null and does something unexpected with.
Using a JSON formatter to pinpoint issues
The fastest way to diagnose a malformed JSON document is to paste it into a JSON formatter that shows inline errors. A good formatter does three things a text editor does not: it highlights exactly the token that caused the failure (not just a character position), it describes the error in terms of the JSON grammar ("expected comma or closing brace" rather than "unexpected '}'"), and it shows you the surrounding context in a tree view so you can see whether you are inside an object or an array.
For large documents — API responses that are tens of thousands of lines long — the tree view is essential. Walking a 50,000-line JSON document looking for a missing quote is not a strategy; it is a waste of an afternoon. Collapse the tree to the top level, expand sections until you find the one that fails to parse, and narrow down from there. Binary search beats linear scan by orders of magnitude.
Configuring your editor to catch errors before runtime
Neither VS Code nor JetBrains IDEs show JSON errors in .jsonfiles by default — you have to open a file with the JSON Language Mode active. In VS Code, check the bottom-right corner of the status bar for the current language mode. If it says "Plain Text," click it and select "JSON" or "JSONC." With JSON mode active, VS Code uses the built-in JSON Language Server to report syntax errors inline, with red squiggles and error descriptions in the Problems panel.
For JSON files that do not have the .json extension (configuration files with custom extensions, API response fixtures, test data), add a file association in VS Code settings:
// settings.json
{
"files.associations": {
"*.jsonresponse": "json",
"*.fixture": "json"
}
}Add a JSON schema association for files that have a known shape, and VS Code will validate content against the schema — showing errors for missing required fields, wrong types, and invalid enum values, not just syntax errors.
Why JSON's strictness is correct, even when it is inconvenient
A reasonable question: why is JSON so strict? No comments, no trailing commas, no single quotes — these are all things that the JavaScript parser handles just fine. Why does JSON refuse them?
The answer is interoperability. JSON is not a JavaScript feature; it is a data interchange format designed to be parsed by any language. Every parser in every language must produce the same result for the same input. The moment you allow ambiguity — a comment that one parser ignores and another parser treats as a string — you lose that guarantee. The strictness is not a limitation of the format; it is the property that makes the format reliable.
JSONC (JSON with Comments) and JSON5 (which adds single quotes, trailing commas, unquoted keys, and more) are pragmatic extensions that make sense for human-authored configuration files. VS Code uses JSONC for its settings files precisely because humans write those files and comments are genuinely useful. But JSONC and JSON5 are not interchange formats — they require specific parsers and should never appear in API responses or data pipelines. Use the right format for the right purpose: strict JSON for machine-to-machine communication, JSONC or TOML for human-authored configuration.
Circular references: the special case JSON.stringify silently breaks
Circular references deserve their own mention because JSON.stringify throws a TypeError: Converting circular structure to JSON error that is not a malformed JSON issue at all — it is a JavaScript object graph issue that prevents serialization from starting. The fix depends on your situation:
// Option 1: Use a replacer function to skip circular references
function safeStringify(obj: unknown): string {
const seen = new Set();
return JSON.stringify(obj, (key, value) => {
if (typeof value === 'object' && value !== null) {
if (seen.has(value)) return '[Circular]';
seen.add(value);
}
return value;
});
}
// Option 2: Use the 'flatted' library for full circular reference support
import { stringify, parse } from 'flatted';
const serialized = stringify(circularObj);
const restored = parse(serialized);