JSON validator

Paste a document and find out whether it is well-formed JSON — and if it is not, exactly which character broke it, on which line, in which column, with the line itself printed and a caret under the spot. Validation runs in this tab; nothing you paste is uploaded.

Indent

Safe to paste production data. There is no upload endpoint, no storage and no share link on this page, so a payload containing customer records or a connection string goes no further than your own browser. That is architecture, not policy — and in 2025 the difference stopped being academic.

What “valid JSON” actually means

JSON is defined by RFC 8259 and by ECMA-404, which describe the same grammar. It is a small grammar — small enough to print in full — and validity is a purely syntactic question. A document is valid if it is exactly one JSON value, optionally surrounded by whitespace, and nothing else.

A JSON value is one of seven things:

ValueWritten asNotes
Object{"a": 1}Zero or more "name": value pairs, comma-separated. Names must be strings in double quotes.
Array[1, 2]Zero or more values, comma-separated. Elements may be of mixed types.
String"text"Double quotes only. Characters below U+0020 must be escaped.
Number-1.5e3Optional minus, integer part, optional fraction, optional exponent. No leading zeros, no +, no hex.
truetrueLowercase.
falsefalseLowercase.
nullnullLowercase.

Whitespace between tokens may only be space (U+0020), horizontal tab (U+0009), line feed (U+000A) or carriage return (U+000D). A non-breaking space pasted from a word processor is not whitespace to a JSON parser; it is an illegal character, and it is invisible, which is why this validator names it explicitly when it finds one.

Things that are valid and surprise people

  • "hello" on its own is a valid JSON document. So is 42, true and null. The old RFC 4627 required the top level to be an object or an array; RFC 7159 removed that restriction in 2014 and RFC 8259 kept the change. Some elderly parsers and some strict API gateways still reject a scalar at the top level.
  • {} and [] are valid — empty is fine.
  • {"": 1} is valid. The empty string is a legal key.
  • {"a": 1, "a": 2} is not forbidden. The spec says names should be unique but does not require it. See below for why that is a security problem.
  • 1e400 is syntactically valid even though it is beyond the range of a double. JSON.parse returns Infinity for it; other parsers differ.
  • "\uD800" — a lone high surrogate with no partner — is accepted by the grammar and by JSON.parse, even though the resulting string cannot be encoded as valid UTF-8.

Things that are invalid and surprise people

  • A trailing comma anywhere: [1, 2,], {"a": 1,}.
  • Comments of any kind: //, /* */, #.
  • Single-quoted strings, and unquoted object keys.
  • NaN, Infinity, -Infinity, undefined.
  • Numbers written as .5, 5., +5, 0x1F, 1_000, 007.
  • A real newline or tab inside a string. They must be \n and \t.
  • A byte order mark before the opening brace. The BOM is invisible, entirely legal in a UTF-8 file, and rejected by every conforming JSON parser.
  • Two documents concatenated. One file, one value.

How this validator reports errors

The browser’s own JSON.parse decides validity, so the verdict matches what your code will do. But JSON.parse messages are terse and engine-specific, so when it refuses, a second pass runs: a strict RFC 8259 scanner that walks the text looking for the first illegal construct and tries to name it in the terms a developer would use.

You get four things:

  1. A named cause. Not “unexpected token” but “Trailing comma before }”, “Unquoted property name: port”, “Unescaped line feed (a real newline) inside a string”.
  2. A position. Line, column and raw character index, so it works whether your editor counts lines or offsets.
  3. The line, with a caret. Long lines are windowed around the caret so that a minified single-line document still produces a readable excerpt.
  4. What to do about it. A hint aimed at the actual cause — that a Windows path needs its backslashes doubled, that a zip code beginning with zero has to be a string, that a document starting with < is an error page.

The scanner is cross-checked against JSON.parse on twenty thousand randomly mutated documents. The two agree on every one about whether the input is valid, so the diagnosis never contradicts the verdict.

Worked examples

1. The error is reported after the mistake

{
  "host": "db.internal"
  "port": 5432
}

Reported at line 3, column 3 — at "port", not at the end of line 2 where the comma is missing. That is inherent to how parsers work: after reading a complete value the parser expects a comma or a closing brace, and it only knows something is wrong when it sees the next string instead. Whenever a JSON error points at a line that looks perfectly fine, look at the line above. It is by far the most common false lead in JSON debugging.

2. The invisible character

{
  "name": "Ada"
}

That document looks correct and may well be, but if the space before "name" was pasted from a PDF or a rich-text email it might be U+00A0, a non-breaking space. To a JSON parser that is not whitespace at all, and the error message from most tools is a bewildering “unexpected token” pointing at a character you cannot see. This validator names it: “Invisible character U+00A0 (a non-breaking space) where a property name was expected”. The same check covers zero-width spaces, ideographic spaces, curly quotes and a stray BOM in the middle of a file.

3. A truncated download

{"users":[{"id":1,"name":"Ada"},{"id":2,"na

Reported as “This string is never closed” at the quote that opens "na. When a document simply stops, the cause is nearly always transport, not syntax: a response read with a fixed-size buffer, a stream consumed before it finished, a curl interrupted, a log rotated mid-write, or a database column too narrow for the value. Check the length of what you received against the Content-Length header before you go looking for a bug in the producer.

What a syntax validator cannot tell you

Valid JSON is a very low bar. It says nothing about whether the document means what you intended:

  • Schema conformance. Whether age is a number, whether email is present, whether status is one of three allowed strings. That is JSON Schema, enforced by a library such as Ajv (JavaScript), jsonschema (Python) or everit (Java).
  • Semantic sanity. {"temperature_celsius": 4000} is perfectly valid JSON.
  • Encoding correctness. A document can be valid JSON and still be mis-decoded on arrival if the producer wrote UTF-8 and the consumer assumed Latin-1. The symptom is é where é belongs — valid JSON containing wrong text.
  • Duplicate-key safety. Since duplicates are not forbidden and parsers resolve them differently — JavaScript keeps the last, some keep the first, some error — a crafted payload can be validated by one service and acted on differently by another. If you consume untrusted JSON, reject duplicate keys explicitly rather than relying on the parser.
  • Size safety. A deeply nested document can exhaust a recursive parser’s stack; a large one can exhaust memory. Both are valid JSON. Bound the depth and the byte length before parsing untrusted input.

Validating JSON without a browser

For files, a scriptable check is usually better than a web page. All of these run locally and exit non-zero on failure, so they drop straight into a pre-commit hook or a CI job:

# jq — prints the parsed document, or an error with a byte offset
jq empty file.json

# Python, in the standard library, no dependencies
python3 -m json.tool file.json > /dev/null

# Node.js
node -e 'JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"))' file.json

# Every .json file in a repository, stopping at the first failure
find . -name '*.json' -not -path './node_modules/*' -print0 \
  | xargs -0 -n1 -I{} sh -c 'jq empty "{}" || echo "FAILED: {}"'

A web page is the better tool when you have a snippet rather than a file, when you want to see where the error is rather than read an offset, or when you want to explore the shape of an unfamiliar payload afterwards. That is why this page hands you the tree view and the statistics the moment the document validates.

Frequently asked questions

Is a single string or number valid JSON?

Yes, under RFC 7159 (2014) and RFC 8259 (2017), which is what modern parsers implement. "hello", 42, true and null are each complete JSON documents. The original RFC 4627 required an object or array at the top level, so very old parsers and a few strict API gateways still refuse them. If you are writing a public API, wrapping scalars in an object costs nothing and avoids the argument.

Why does the error point at a line that looks fine?

Because a parser reports where it noticed the problem, not where you made it. A missing comma is detected at the beginning of the next value; an unclosed brace is detected at the end of the file. When the flagged line looks correct, read the line above it, and check whether a string opened earlier was ever closed.

My JSON is valid in my editor but fails here. Why?

Almost always one of three things. Your editor may be validating JSON5 or JSONC rather than JSON — VS Code does this for files it recognises as settings, which is why comments look fine there. Your file may begin with a byte order mark that the editor hides. Or the copy that reached the clipboard may be a fragment: copying a folded region or a selection that stops at the viewport edge is easy to do without noticing.

Does the validator modify my document?

It does not touch the text in the input box. The formatted and minified output shown below are newly serialised from the parsed value, which is why they can differ in whitespace, number formatting and \u escapes. Your original stays exactly as pasted.

Can I validate a very large file here?

Several megabytes, comfortably. Above about 300 KB the tool stops re-checking on every keystroke and waits for you to press Format or Minify. Beyond a few hundred megabytes, no browser page is the right answer — use a streaming parser such as jq, Python’s ijson or Jackson’s streaming API, which never hold the whole document in memory.

Is my data sent anywhere for validation?

No. Validation is JSON.parse plus a scanner written in the JavaScript on this page, both running in your tab. There is no upload endpoint and nothing is stored. Open the Network panel of your developer tools and press Format — your document does not appear in any request, because no code here is capable of sending it.

What is the difference between valid JSON and a valid API response?

Validity is syntax. An API contract is everything else: required fields, types, enumerations, formats, ranges, and the status code and content type the response arrived with. A 500 response carrying {"error":"boom"} is perfectly valid JSON. Validate syntax here, then validate meaning with a JSON Schema in your tests.

Related pages

Related tools