All articles
52 articles · updated weekly See our Tools
All articles
Tutorials

How to Validate JSON and Find Syntax Errors

Trailing commas, single quotes, unclosed brackets — the most common JSON syntax errors and how to find the exact line without guessing.

COVER · Tutorials

The API returned 400. The log says Unexpected token. The payload looks fine. You open DevTools, run JSON.parse(...) — same error. And now you're hunting for a misplaced comma in a 300-line minified string.

This happens more often than it should. Here's how to make that debugging session as short as possible.

The JSON syntax errors that show up constantly

JSON has a small, strict grammar. No comments, no trailing commas, no single quotes, no undefined. Any deviation and the parser stops immediately — it doesn't guess, it doesn't skip, it fails.

The errors that come up in practice:

Trailing comma

{
  "name": "Rafael",
  "role": "dev",
}

The comma after "dev" is invalid. JSON doesn't allow trailing commas — unlike JavaScript, where they're fine. This one typically appears when you delete a property from the middle of an object and forget to clean up the comma on the new last line.

Single quotes instead of double quotes

{
  'name': 'Rafael'
}

JSON requires double quotes. Single quotes are JavaScript, YAML, Python — not JSON. The error is subtle visually, especially if you spend most of your time writing JS object literals.

Unquoted keys

{
  name: "Rafael"
}

Valid in JS, invalid in JSON. Every key must be in double quotes, no exceptions.

Missing comma between properties

{
  "name": "Rafael"
  "role": "dev"
}

The parser tries to read "role" as a continuation of "Rafael" and fails. This one appears when you add a new field to a large object and forget the comma at the end of the previous line.

Unclosed brackets or braces

{
  "items": [
    {"id": 1},
    {"id": 2}
  
}

Missing ]. The parser hits } and doesn't find what it expects. In deeply nested JSON, tracking down where a bracket went missing is genuinely annoying.

undefined or comments

{
  "debug": undefined,
  // temporary config
  "timeout": 30
}

undefined is not a valid JSON value — use null. Comments don't exist in JSON either. If you need comments in config files, use JSONC (JSON with Comments), which VS Code and TypeScript understand, but which standard parsers reject.


How to find the exact error line without guessing

Unexpected token ',' at position 142 is not immediately useful when the file is 2000 characters long. Most parsers give you line and column information — the question is knowing where to look.

In the browser (DevTools):

try {
  JSON.parse(yourJson);
} catch (e) {
  console.log(e.message);
  // SyntaxError: Unexpected token '}' at position 89
}

The position is character offset from the start. Not directly a line number, but you can use an editor to jump to that character. In VS Code: Ctrl+G to go to a line. From the terminal, echo "..." | python3 -m json.tool gives line and column.

In Python:

import json

try:
    data = json.loads(text)
except json.JSONDecodeError as e:
    print(f"Error at line {e.lineno}, column {e.colno}: {e.msg}")

JSONDecodeError inherits from ValueError and exposes lineno, colno, and doc. You can extract the exact offending line with e.doc.split('\n')[e.lineno - 1].

In Node.js:

try {
  JSON.parse(text);
} catch (e) {
  // e.message has position but not line/column directly
  // For precise line/column, use an external validator
}

Node's native JSON.parse doesn't expose line and column — only character position. For that level of detail, an external linter or validator is more practical.


Online JSON validation: when it's worth it

For large payloads or when debugging a file that came from outside your control (API response, database export, config file from another team), an online validator saves time. You paste, it points to the exact line.

I use JSON Formatter for this — especially when I need to format before inspecting, because minified single-line JSON is unreadable for any kind of diff or inspection. The validator shows the error with line and column, and you can navigate the structure before fixing it.

If the JSON is minified, format it first. Finding a trailing comma in {"name":"a","role":"b",} is trivial — finding it in 50KB on one line is not.


Validating against a schema: beyond syntax

Valid syntax doesn't mean correct data. A JSON can parse without errors and still be wrong for your application: required field missing, wrong type ("age": "thirty"), value out of expected range.

For that level of validation, you need JSON Schema. If you want a more foundational overview of how JSON works before diving into schemas, there's an intro post at What is JSON and how does it work.

A basic schema that validates types and required fields:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["name", "age"],
  "properties": {
    "name": { "type": "string" },
    "age": { "type": "integer", "minimum": 0 }
  }
}

Against this schema, {"name": "Rafael", "age": "thirty"} fails with must be integer on the age field. The syntax is valid — the type is wrong.

Libraries like AJV (JavaScript), jsonschema (Python), or opis/json-schema (PHP) handle this programmatically. To test a schema before wiring it into code, an online validator with JSON Schema support is faster than spinning up a script.


JSON in config files: specific gotchas

Config files like package.json, tsconfig.json, and appsettings.json have some quirks that cause errors:

tsconfig.json allows comments; package.json doesn't. TypeScript uses JSONC internally, so comments in tsconfig.json work in VS Code and the compiler. But if you feed that file to JSON.parse in your own code, it breaks.

Large numbers become floats. JSON's spec doesn't distinguish between integers and floats — everything is number. Numbers larger than 2^53 - 1 lose precision when parsed in JavaScript because they don't fit in a float64. If you're working with large IDs (like Twitter/X IDs), this is a real problem. The fix is to transmit those values as strings.

Duplicate keys are "valid" but dangerous. The JSON spec doesn't prohibit duplicate keys in an object. The behavior is undefined — different parsers resolve it differently. Some use the last value, some the first, some throw an error. Don't rely on duplicate keys for any logic.


Frequently asked questions

Why doesn't JSON allow trailing commas?

Because the JSON spec (RFC 8259) was designed to be simple and unambiguous. Trailing commas complicate parsing and create edge cases. The decision was to keep the grammar minimal. If you want trailing commas, use JavaScript (where they're valid), YAML, or JSONC — which is an unofficial JSON extension that adds comments and trailing commas, used by VS Code and TypeScript.

How do I validate JSON from the command line without installing anything?

If you have Python installed (standard on any Unix/Mac system):

echo '{"name": "test",}' | python3 -m json.tool
# Expecting property name enclosed in double quotes: line 1 column 18 (char 17)

With Node.js:

node -e "JSON.parse(require('fs').readFileSync('file.json', 'utf8'))"

With jq (if installed):

cat file.json | jq .

jq is the most informative — it shows line and column with visual context around the error.

What's the difference between invalid JSON and malformed JSON?

In practice, they're synonyms. Technically, "malformed" refers to grammar violations (trailing commas, wrong quotes) while "invalid" can also include schema or semantic violations. But in most technical conversations and error messages, the terms are used interchangeably.

Does JSON Schema work for any JSON?

Yes, with one caveat: JSON Schema defines a contract, and you have to write that contract. It doesn't automatically infer what's correct for your use case — you declare what you expect (types, required fields, ranges, string patterns) and the validator applies it. For arbitrary payloads where you only want to check syntax, JSON.parse is already sufficient.


Valid syntax is necessary, not sufficient

Syntactically valid JSON is just the starting point. The parser accepting the data doesn't mean the application will. The right sequence is: validate syntax first (JSON.parse or any validator), then validate schema if the data comes from outside your control (external API, user input, config file managed by another team).

For internal data you produce yourself, integration tests that verify the contract are more useful than runtime schema validation — because the problem is usually in serialization, not in the input.

A syntax error is the easiest kind to fix. Unexpected token is never ambiguous: something is wrong at that point, and any parser or validator shows exactly where. The hard part is when the JSON parses without error but the data is semantically wrong — and that's where you need schema.


Note: the editorial content ends here. What follows is a pointer to a related tool.


To validate and format JSON without leaving the browser — including locating the exact line of a syntax error — I use JSON Formatter. It works offline, doesn't send your data anywhere, and formats before validating so the structure is readable when you're debugging.

RD
Author
Rafael Duarte
Desenvolvedor backend com passagem por fintech e SaaS B2B — trabalhou em times que escalaram APIs de zero a milhões de requisições. Carrega cicatrizes de produção suficientes para ter opiniões fortes sobre ferramentas, padrões e decisões de arquitetura. Não é acadêmico: leu a RFC do UUID quando precisou escolher entre v4 e v7 para uma tabela de alta escrita.
View profile