JSON Validator
Syntax-check JSON with the exact line, column and probable cause of every error — entirely on this device.
The verdict appears here as you type — with the exact position when something's wrong.
Press ? for shortcuts
Do it offline:$ jq empty file.json
How to use it
- Paste or drop your JSON. Small inputs are checked on every keystroke; from 2 MB a button names the exact size it is about to validate, and ⌘/Ctrl+Enter runs it.
- Read the verdict panel: stats for a valid document — keys, depth, size, top-level type — or the first hard error with a code frame, a mark in the editor gutter, and a Jump-to-error button.
- Work down the advisory list: a bounded continuation scan lists further suspect spots — trailing commas, single quotes, unquoted keys, comments — to clear before re-validating once.
- Copy or download the validation report, or use Share to fold the input into a link. The report carries the verdict, every finding with its position, and the code frame — ready for an issue tracker.
Paste JSON and get a verdict as you type: a green Valid JSON panel with document stats, or the first hard error with its line, column and probable cause — plus an advisory list of what else looks wrong. Everything runs on this device; nothing is uploaded. When you have your answer, copy a plain-text validation report ready for a bug ticket or code review.
How it works
Two documents define JSON — RFC 8259 from the IETF and ECMA-404 from Ecma International, kept deliberately aligned — and validity is pure grammar: one value (object, array, string, number, true, false or null) built from structural tokens with whitespace between them. No schema, no semantics: a text either derives from that grammar or it does not, which is why a yes-or-no verdict needs no knowledge of what your data means.
The verdict here comes from the same streaming tokenizer that powers our JSON Formatter, run in strict mode with the output discarded — one grammar, one source of truth. Because that tokenizer walks the input a character at a time and counts every line break, the first offending character carries an exact 1-based line, column and offset the instant it is reached. The message adds a ±2-line code frame with a caret under it, and a probable cause matched from the surrounding pattern.
A strict parser must stop at the first violation — after a broken token, every later character is formally ambiguous. Honest, but stingy; so a second, purely advisory scan continues across the remainder, looking for recognizable trouble: trailing commas, single-quoted strings, unquoted property names, comments, smart quotes from chat clients, Python literals like True and None, and concatenated documents. Findings are labeled as probabilities, not verdicts, and the list stops at the first 100.
Strictness cuts both ways: JSON5 and JSONC exist because hand-written config wants comments and trailing commas, so when a failure is really a dialect mismatch, the probable cause says so. And a green verdict is not the whole story — duplicate keys, integers beyond ±2⁵³, members named __proto__ and nesting past 1,000 levels are all valid JSON that misbehaves in real parsers, and each surfaces as a warning on the pass state rather than sailing through in silence.
Examples
{'name': 'ana'}Unexpected "'" at line 1, column 2 — probable cause: single-quoted strings are JSON5, not JSON; use double quotes.The most pasted mistake of all: JavaScript object literals and Python dict dumps both print single quotes. The advisory scan flags the remaining quote pairs, so one pass finds every one.
{"a": 1,}Unexpected '}' at line 1, column 9 — probable cause: trailing comma after the last property.The caret lands on the closing brace, where the grammar breaks — but the probable cause looks one token back and blames the comma that put it there.
{"id": 72057594037927937, "safe": true}Valid · 2 keys · depth 1 · 39 BValid — and still flagged. 72057594037927937 lies beyond 2⁵³, so a W_JSON_PRECISION warning anchors those digits before some downstream JSON.parse quietly rounds them to 72057594037927940.
4242 is valid JSONA bare scalar is a complete document: the stats read zero keys, depth zero, top-level type number. Anything that rejects this is enforcing the 2006 rules, not current JSON.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
A byte-order mark is tolerated — and reported
Windows tooling and PowerShell redirects habitually prepend U+FEFF to UTF-8 files. RFC 8259 lets implementations ignore a leading BOM and forbids adding one, so this page validates the document and posts a warning — “Leading byte-order mark ignored” — while JSON.parse and other strict consumers throw the moment they meet those bytes.
Whitespace-only gets a verdict; an empty pane gets none
An empty pane just waits — nothing was submitted, nothing is judged. Spaces and newlines, though, are a document with no value in it, which the grammar cannot accept. The refusal stays gentle: “Only whitespace at line 1, column 1 — probable cause: a JSON document needs a value; even 42 or null is valid.”
UTF-16 files are recognized by their first two bytes
RFC 8259 mandates UTF-8 for JSON exchanged between systems, yet Windows exports still arrive as UTF-16. Dropped files are sniffed by byte-order mark — FF FE or FE FF — decoded accordingly, and validated as text, with a note naming the encoding. Line and column numbers refer to the decoded characters, never to byte offsets in the file.
Nesting: warned at 1,000 levels, refused at 100,000
The tokenizer is iterative, so depth cannot crash this page — the cap is documented policy, not a stack limit: “Nesting is deeper than the documented 100,000-level cap.” The warning arrives far earlier, at 1,000 levels (W_JSON_DEEP_NESTING): recursive parsers in the wild overflow well below the cap.
Numbers are judged as digits, never as floats
The grammar sets no precision limit, so a 40-digit integer is valid JSON and passes here untouched. On top of the verdict, W_JSON_PRECISION anchors the digits of any integer beyond ±2⁵³ — the point where JavaScript consumers round, and two IDs differing in the last digit become one.
__proto__ is valid JSON with a security footnote
Nothing in RFC 8259 forbids a member named __proto__ or constructor — and nothing in JavaScript forgives one. Merged naively into a live object, they can rewrite a prototype chain: the classic prototype-pollution attack. The document passes; W_JSON_PROTO_KEY points at the member so trusting it is your decision, not an oversight.
The report is built for pasting, not screenshotting
Copy, ⌘/Ctrl+S and the empty-selection copy all produce the same plain-text artifact: a header beginning “JSON validation report — ” with this page's address, then the verdict, each finding at its line and column, and the code frame. Run it on [1, 2, 3,] and the report's error line reads: “Unexpected ']' at line 1, column 10 — probable cause: trailing comma after the last element.”
Common errors
Unexpected '}' at line 3, column 1 — probable cause: trailing comma after the last property.- The comma after a final property promises another that never arrives, so the closing brace becomes the first illegal character. Delete the comma — and if a machine wrote it, fix the serializer, not the file.
Unexpected "'" at line 1, column 11 — probable cause: single-quoted strings are JSON5, not JSON; use double quotes.- Keys and values take double quotes, always. Single quotes usually mean a JavaScript object literal or a Python dict's repr — debugger output, not serialization. Regenerate with JSON.stringify or json.dumps rather than re-quoting by hand.
Unexpected 'r' at line 3, column 3 — probable cause: property names must be double-quoted.- Bare property names are object-literal syntax that no JSON parser accepts; every key needs its own double quotes. The advisory list under the first error marks the remaining bare keys, so one validation pass finds them all.
Unexpected '/' at line 2, column 3 — probable cause: comments are not valid JSON (JSONC and JSON5 allow them).- JSON's author removed comments deliberately, to stop them being abused as parsing directives. Config formats that allow them — tsconfig.json, VS Code settings — are JSONC, a different grammar. Strip the comments or hand the file to a JSONC-aware reader.
Unexpected end of input at line 1, column 15 — probable cause: the document is incomplete or truncated.- The text ran out while a value was still open — almost always truncation in transit: a log line clipped at a length limit, a response cut by a timeout, a copy missing the final brace. The column says exactly how much arrived.
Unexpected '{' at line 1, column 10 — probable cause: multiple JSON documents; this looks like NDJSON / JSON Lines.- One run judges one document, and this second { starts another. Concatenated or line-delimited records are NDJSON — a real format, just a different one. Validate one record here, or hand the stream to jq.
Unexpected control character at line 1, column 19 — probable cause: raw line breaks and control characters inside strings must be escaped (\n, \t, …).- Inside a JSON string a literal line break or tab is forbidden — they must travel as the escapes \n and \t. This appears when multi-line text is spliced into a hand-assembled string; let a serializer produce the escapes instead of concatenating.
Invalid number at line 1, column 10 — probable cause: numbers cannot have leading zeros.- A JSON number may not start with a superfluous zero — a rule inherited from languages where 08 read as broken octal. If the zero carries meaning, the value was never a number: padded ports, postcodes and phone numbers belong in strings.
Unexpected 'N' at line 1, column 11 — probable cause: NaN and Infinity are JSON5 values, not valid JSON.- IEEE 754 defines NaN and Infinity; JSON deliberately has no spelling for either. JavaScript's JSON.stringify writes null in their place and Python's json module emits them only behind a non-standard flag. Pick a representation — null, a string marker, an omitted field — and encode it deliberately.
Input is larger than the 50 MB limit for this tool.- Past the cap the page declines the whole document — a verdict on a slice would be a lie with a green tint. The same check runs locally at any size: jq empty file.json prints nothing for valid input and the first error with its position otherwise.
FAQ
Why does JSON.parse throw “Unexpected token o in JSON at position 1”?
Because the text handed to it starts with something like [object Object]: position 0 holds the bracket, and the o of “object” is the first impossible character — the signature of an object concatenated into a string, or of parsing a value twice. Paste the exact text here and the same character is named with a line, column and code frame instead of a bare byte offset.
Is 42 valid JSON?
Yes. Under RFC 8259 any single value is a complete document — 42, null, true and "hello" all pass. A tool that rejects a bare scalar is enforcing RFC 4627, the 2006 edition that demanded an object or array at the top level; current standards dropped that rule.
Are duplicate keys valid JSON?
Grammatically yes: RFC 8259 says object names “should” be unique — should, not must. In practice they are a trap: parsers disagree about which occurrence wins, and security tools treat that disagreement as a smuggling channel. This page passes the document and warns instead: “duplicate key `tag` at lines 1 and 1 — most parsers keep the last”.
Does this page validate against a JSON Schema?
No — this page answers whether your text is JSON at all; JSON Schema answers whether a parsed document has the shape a contract expects: required fields, types, ranges. A dedicated JSON Schema validator is planned for this site. Until it ships, settle syntax here first — schema tooling gives baffling answers when the input does not even parse.
Can I validate NDJSON or JSON Lines here?
Not as a stream — the second document trips the trailing-content error, which names NDJSON precisely so the failure explains itself. Paste one line to validate a single record. For whole files, jq empty consumes a sequence of documents in one pass, which is why it is the CLI line under this tool.
What is the difference between JSON, JSON5 and JSONC?
JSON is the interchange grammar the standards define: double quotes only, no comments, no trailing commas. JSONC adds comments — and, in most readers, trailing commas — for editor config. JSON5 goes further: unquoted keys, single quotes, hex numbers, plus signs. When text fails here on a dialect feature, the probable cause names the dialect — a broken file and a mislabeled one are different problems.
Is it safe to paste production payloads here?
The verdict is computed in this tab — big inputs run in a worker thread on your machine, the network panel stays silent after load, and it works offline. The deliberate exception is Share, which encodes your input into the link itself: a URL containing a secret is a secret, and the dialog warns before one is created.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Validate now — required from 2 MB, where the button names the size; below that, an immediate re-run.
- ⌘/Ctrl + S
- Download the validation report as a .txt file — the help overlay notes it replaces the browser's save-page shortcut here.
- ⌘/Ctrl + C
- Copy the validation report when focus is inside the tool and no text is selected; with a selection, copying behaves natively.
- ⌘/Ctrl + Shift + C
- Copy the report regardless of what is selected.
- t
- Cycle the color theme (single keys stay inert in text fields, during IME composition, and when disabled in settings).
- ? or ⌘/Ctrl + /
- Open the shortcuts overlay, browser-conflict notes included.
- Esc
- Dismiss the topmost dialog or overlay — never your input.