DEV Community

Michael Lip
Michael Lip

Posted on • Originally published at zovo.one

Why Your JSON Is Probably Invalid (And How to Fix It)

I've code-reviewed hundreds of pull requests that include JSON configuration files, API responses, or fixture data. The number of times I've seen technically invalid JSON that "works" because the parser is lenient is staggering. Here are the seven mistakes I see most often, why they're wrong according to the spec, and how to fix them.

1. Trailing commas

This is by far the most common offender.

{
  "name": "Michael",
  "age": 30,
}
Enter fullscreen mode Exit fullscreen mode

That trailing comma after 30 is invalid JSON. JavaScript objects allow it. Python dicts allow it. JSON does not. The spec (RFC 8259) explicitly requires that the comma only appear between values, not after the last one.

Every major browser's JSON.parse() will throw a SyntaxError on this. The reason you might not notice is that many config file parsers — VS Code's settings.json parser, for example — use a superset called JSON5 or JSONC that tolerates trailing commas. But if you're sending this over an API or feeding it into a strict parser, it breaks.

2. Single quotes

{
  'name': 'Michael'
}
Enter fullscreen mode Exit fullscreen mode

JSON requires double quotes. Both keys and string values must be wrapped in double quotes, never single quotes. This trips up Python developers especially, because Python's json.dumps() outputs double quotes but developers hand-writing JSON often reach for singles out of habit.

3. Unquoted keys

{
  name: "Michael"
}
Enter fullscreen mode Exit fullscreen mode

In JavaScript, object keys don't need quotes unless they contain special characters. In JSON, every key must be a double-quoted string. No exceptions. This is the mistake that makes the difference between a JavaScript object literal and JSON most obvious. They look similar but they are different formats with different rules.

4. Comments

{
  "name": "Michael", // this is my name
  "debug": true /* enable debug mode */
}
Enter fullscreen mode Exit fullscreen mode

JSON does not support comments. Not single-line, not multi-line, not at all. Douglas Crockford, who created JSON, deliberately excluded comments because he saw people using them to embed parsing directives, which defeated the purpose of a simple data interchange format.

This is the single biggest pain point with using JSON for configuration files, and it's why formats like JSONC (JSON with Comments), YAML, and TOML exist. TypeScript's tsconfig.json is actually JSONC. Package.json is strict JSON. Know which one you're dealing with.

5. Undefined and NaN

{
  "value": undefined,
  "ratio": NaN
}
Enter fullscreen mode Exit fullscreen mode

JSON supports exactly these value types: strings, numbers, booleans (true/false), null, arrays, and objects. That's it. undefined is a JavaScript concept that doesn't exist in JSON. NaN and Infinity are IEEE 754 floating-point values that JSON explicitly excludes.

If you run JSON.stringify({ value: undefined }) in JavaScript, the key is silently dropped from the output. If you try to stringify NaN, it becomes null. This silent conversion causes bugs that are genuinely hard to trace.

6. Hex numbers and leading zeros

{
  "color": 0xFF0000,
  "zipcode": 01234
}
Enter fullscreen mode Exit fullscreen mode

JSON numbers must be decimal. No hex (0x), no octal (0o), no binary (0b). Leading zeros are also forbidden because some parsers interpret them as octal notation, which creates ambiguity. The zipcode above would need to be a string: "01234".

The number format JSON accepts is straightforward: an optional minus sign, digits (no leading zeros except for the number zero itself), an optional decimal point followed by digits, and an optional exponent. That's the complete grammar for JSON numbers.

7. Multiline strings

{
  "description": "This is a
  long description"
}
Enter fullscreen mode Exit fullscreen mode

JSON strings cannot span multiple lines. If you need a newline in a string value, use the escape sequence \n. This catches people writing JSON by hand because it feels natural to break a long string across lines.

{
  "description": "This is a\nlong description"
}
Enter fullscreen mode Exit fullscreen mode

The Content-Type that matters

When serving JSON from an API, the correct Content-Type header is application/json. Not text/json (which is not a registered MIME type), not text/plain (which some browsers will refuse to parse as JSON for security reasons), and not application/javascript (which is for actual JavaScript code).

Debugging JSON from the command line

The jq command-line tool is the fastest way to validate and explore JSON. If you don't have it installed, you should.

Validate a file:

jq . data.json
Enter fullscreen mode Exit fullscreen mode

If the JSON is invalid, jq prints an error pointing to the exact line and character position. If it's valid, it pretty-prints the output.

Extract a field:

cat response.json | jq '.data.users[0].name'
Enter fullscreen mode Exit fullscreen mode

Filter an array:

cat data.json | jq '.items[] | select(.price > 100)'
Enter fullscreen mode Exit fullscreen mode

Format inline JSON from a curl response:

curl -s https://api.example.com/data | jq .
Enter fullscreen mode Exit fullscreen mode

For quick validation without installing anything, Python works too:

python3 -m json.tool < data.json
Enter fullscreen mode Exit fullscreen mode

This reads from stdin, validates the JSON, and pretty-prints it. If the JSON is invalid, it prints the error with a line number.

JavaScript objects are not JSON

I keep coming back to this because it's the root cause of most of these mistakes. When you write const obj = { name: "Michael" } in JavaScript, that's an object literal. It follows JavaScript syntax rules. When you call JSON.stringify(obj), the output follows JSON syntax rules. They overlap but they aren't identical.

The test is simple: if you can't paste it into JSON.parse() and get back the same data, it's not valid JSON.

For quick formatting and validation without setting up a local environment, I keep a JSON formatter at zovo.one/free-tools/json-formatter that highlights syntax errors and shows you exactly where your JSON breaks.

Knowing the spec saves hours of debugging. The rules are small enough to memorize. Double-quoted keys. Double-quoted strings. No trailing commas. No comments. No undefined. No hex. No multiline strings. Seven rules. That's JSON.


I'm Michael Lip. I build free developer tools at zovo.one. 350+ tools, all private, all free.

Top comments (0)