DEVESSENTIALS

JSON Validator

Paste JSON to check whether it is valid per RFC 8259. The validator runs your browser's own JSON.parse as you type and shows either "Valid JSON" or the exact parser error with the position where parsing stopped. Below the tool: what each error message means in Chrome, Firefox and Python, and the problems that valid JSON can still hide. 100% client-side — nothing is sent to any server.

What "valid JSON" means

Valid JSON is text that a strict parser accepts under RFC 8259: double-quoted keys and strings, no trailing commas, no comments, numbers in plain decimal notation (no NaN, Infinity, hex or leading zeros), only true, false and null as literals, and nothing after the top-level value except whitespace. Any single value is a valid document, so 42 and "ok" pass too.

This validator checks exactly that and nothing more. Because it uses the browser's parser, the error you see here is the one your front-end code will throw. In Chrome and Edge it is the same text Node.js prints; Firefox and Safari word it differently.

JSON error messages by runtime

The same mistake produces different messages in each runtime, which makes them hard to search for. V8 (Chrome, Edge, Node.js) gives a 0-based character position; Firefox and Python give a 1-based line and column. Recent V8 versions append (line L column C) as well, and older V8 (Node.js 18 and earlier) used the form Unexpected token } in JSON at position 7. Python's "Illegal trailing comma" wording is new in 3.13; earlier versions report a trailing comma as Expecting property name enclosed in double quotes or Expecting value.

Trailing comma

{"a":1,}
  • Chrome / Node.js: Expected double-quoted property name in JSON at position 7 (line 1 column 8)
  • Firefox: JSON.parse: expected double-quoted property name at line 1 column 8 of the JSON data
  • Python: Illegal trailing comma before end of object: line 1 column 7 (char 6)

Delete the comma before } or ]. In an array ([1,2,]) V8 instead reports Unexpected token ']' and Firefox "unexpected character".

Single quotes or unquoted keys

{'a':1}
  • Chrome / Node.js: Expected property name or '}' in JSON at position 1 (line 1 column 2)
  • Firefox: JSON.parse: expected property name or '}' at line 1 column 2 of the JSON data
  • Python: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

Use double quotes for every key and string. {a:1} produces the same messages. This usually means the text is a JavaScript object literal or Python repr(), not JSON.

Comments

{"a":1 // note
}
  • Chrome / Node.js: Expected ',' or '}' after property value in JSON at position 7 (line 1 column 8)
  • Firefox: JSON.parse: expected ',' or '}' after property value in object at line 1 column 8 of the JSON data
  • Python: Expecting ',' delimiter: line 1 column 8 (char 7)

JSON has no comments. Remove them, or keep the file as JSONC/JSON5 and only feed it to tools that read that dialect (tsconfig.json and VS Code settings are JSONC). A comment at the very start gives Unexpected token '/' in V8.

NaN, Infinity or undefined

{"a":NaN}
  • Chrome / Node.js: Unexpected token 'N', "{"a":NaN}" is not valid JSON
  • Firefox: JSON.parse: unexpected character at line 1 column 6 of the JSON data
  • Python: No error: json.loads returns {'a': nan}

Use null or a string. Python's json.dumps writes NaN by default, which is how these values end up in files; pass allow_nan=False to make it raise instead.

Truncated document or missing bracket

{"a":1
  • Chrome / Node.js: Expected ',' or '}' after property value in JSON at position 6 (line 1 column 7)
  • Firefox: JSON.parse: end of data after property value in object at line 1 column 7 of the JSON data
  • Python: Expecting ',' delimiter: line 1 column 7 (char 6)

A position equal to the input length means the parser ran out of text. Check for a cut-off log line or response, or count brackets from the error position backwards.

Raw newline or tab inside a string

{"a":"line1
line2"}
  • Chrome / Node.js: Bad control character in string literal in JSON at position 11 (line 1 column 12)
  • Firefox: JSON.parse: bad control character in string literal at line 1 column 12 of the JSON data
  • Python: Invalid control character at: line 1 column 12 (char 11)

Characters below U+0020 must be escaped: \n, \t, \r. This happens when JSON is built by string concatenation; use JSON.stringify or json.dumps instead.

Byte order mark (BOM) at the start

\uFEFF{"a":1}  (invisible first character)
  • Chrome / Node.js: Unexpected token '', "{"a":1}" is not valid JSON
  • Firefox: JSON.parse: unexpected character at line 1 column 1 of the JSON data
  • Python: Unexpected UTF-8 BOM (decode using utf-8-sig): line 1 column 1 (char 0)

The error at position 0 shows an apparently empty token. Strip it: text.replace(/^\uFEFF/, "") in JavaScript, or open the file with encoding="utf-8-sig" in Python. Windows editors and PowerShell's Out-File are common sources.

An HTML page instead of JSON

<!DOCTYPE html>...
  • Chrome / Node.js: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
  • Firefox: JSON.parse: unexpected character at line 1 column 1 of the JSON data
  • Python: Expecting value: line 1 column 1 (char 0)

Not a syntax problem in your JSON: the server returned an HTML error or login page. Check response.status and the Content-Type header before calling response.json().

Two documents back to back

{"a":1}{"b":2}
  • Chrome / Node.js: Unexpected non-whitespace character after JSON at position 7
  • Firefox: JSON.parse: unexpected non-whitespace character after JSON data at line 1 column 8 of the JSON data
  • Python: Extra data: line 1 column 8 (char 7)

Wrap the values in an array, or treat the input as NDJSON (one document per line) and parse each line separately.

Empty input

(empty string)
  • Chrome / Node.js: Unexpected end of JSON input
  • Firefox: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data
  • Python: Expecting value: line 1 column 1 (char 0)

An empty body, often from a 204 No Content response or an unread stream. Check the length before parsing.

To find a V8 position in a large file, paste it here and use the editor's line numbers, or run text.slice(pos - 20, pos + 20) on the string to see the surrounding characters. When there are many errors at once, the JSON repair tool fixes quotes, commas and comments in one pass, and how to fix broken JSON walks through each fix by hand.

Valid JSON that still causes bugs

Passing validation only means the text parses. These inputs are valid, so no validator flags them, but they change your data silently:

Duplicate keys

JSON.parse('{"role":"user","role":"admin"}')
// { role: "admin" }  (last one wins, no error)

RFC 8259 only says keys "SHOULD" be unique. JavaScript, Python and jq keep the last value; some other parsers keep the first or reject the document. That disagreement has been used to slip a different value past a validating service. JSON.parse cannot detect duplicates, so neither can this page; in Python you can:

import json

def reject_duplicates(pairs):
    keys = [k for k, _ in pairs]
    dupes = sorted({k for k in keys if keys.count(k) > 1})
    if dupes:
        raise ValueError(f"duplicate keys: {dupes}")
    return dict(pairs)

json.loads('{"role":"user","role":"admin"}', object_pairs_hook=reject_duplicates)
# ValueError: duplicate keys: ['role']

Large integers lose precision

JSON.parse('{"id": 9007199254740993}').id
// 9007199254740992  (off by one, no error)

JSON.parse('1e400')
// Infinity

JavaScript numbers are 64-bit floats, exact only up to Number.MAX_SAFE_INTEGER (9,007,199,254,740,991). 64-bit database IDs and snowflake IDs above that are rounded silently. The usual fix is to send them as strings. Python's json keeps integers exact, so the same payload can give different IDs in a Python backend and a JavaScript front end. Chrome 114+ and Node.js 21+ pass the original source text to a reviver ((key, value, context) => context.source), which lets you convert such fields to BigInt.

Encoding problems

RFC 8259 requires UTF-8 for JSON exchanged between systems. A file saved as Latin-1 or UTF-16 may parse but turn é into é. Lone surrogate escapes such as "\uD800" parse in JavaScript and Python but fail later when the string is encoded to UTF-8.

Validate JSON from the command line or CI

Each of these exits with a non-zero status on invalid input, so they work in scripts and pre-commit hooks:

# Python (no install); prints the error with line and column
python3 -m json.tool data.json > /dev/null

# jq; "empty" parses the input and prints nothing if it is valid
jq empty data.json

# Node.js; same parser and messages as Chrome
node -e 'JSON.parse(require("fs").readFileSync(process.argv[1], "utf8"))' data.json

Note that readFileSync(..., "utf8") keeps a BOM, so a file saved with one fails in Node.js even when it opens fine in an editor.

Syntax vs schema

Syntax validation answers "can this be parsed?". Schema validation answers "is this the data my code expects?": required fields, types, formats and ranges. This tool does only the first. For the second, describe the shape in JSON Schema and check it in your code or CI, for example with Ajv:

import Ajv from "ajv";

const validate = new Ajv().compile({
  type: "object",
  required: ["id", "email"],
  properties: { id: { type: "integer" }, email: { type: "string" } },
});

validate({ id: "42" });          // false
console.log(validate.errors);    // [{ instancePath: "", message: "must have required property 'email'" ... }]

Ajv stops at the first error unless you pass { allErrors: true }, which is why only the missing email is reported above and not the string id.

Learn more

Browse all developer guides →

Frequently Asked Questions

Does this JSON validator check against a JSON Schema?▾

No. It checks syntax only: whether the text is well-formed JSON per RFC 8259, using your browser's native JSON.parse. It does not check required fields, types or value ranges.

For that you need JSON Schema and a schema validator such as Ajv (JavaScript) or jsonschema (Python), run in your own code or CI. The section "Syntax vs schema" on this page shows a minimal Ajv example.

Why does the same JSON fail in my browser but load fine in Python?▾

Parsers disagree at the edges. Python's json module accepts NaN, Infinity and -Infinity by default (they are not valid JSON), while JSON.parse in browsers and Node.js rejects them. The reverse also happens: a file saved with a UTF-8 byte order mark (BOM) loads in tools that strip it but fails in JSON.parse with "Unexpected token" at position 0.

If data crosses language boundaries, validate it with a strict parser (this page, or JSON.parse in Node.js) rather than the most lenient one in your stack.

Why does JSON.parse(undefined) say '"undefined" is not valid JSON'?▾

JSON.parse converts its argument to a string first. undefined becomes the text "undefined", and a plain object becomes "[object Object]", neither of which is JSON. This usually means a variable you expected to hold a JSON string is empty (for example localStorage.getItem returned null, or a response body was never read) or already holds a parsed object. Log typeof value before parsing.

Is a bare number or string valid JSON?▾

Yes. RFC 8259 (2017) allows any JSON value at the top level, so 42, "hello", true and null are all valid JSON documents. The older RFC 4627 required an object or array, and a few old parsers still enforce that. JSON.parse and Python's json.loads both accept top-level scalars.

What is the maximum size of a valid JSON file?▾

The JSON specification imposes no size limit. Practical limits come from the parser: JSON.parse needs the whole document as one string, and V8 (Chrome, Node.js) caps strings at roughly 512 million characters on 64-bit builds. Browsers usually run out of memory well before that once the parsed objects are built.

For files in the hundreds of megabytes, use a streaming parser (stream-json in Node.js, ijson in Python) or a line-delimited format such as NDJSON.