JSON Schema Validator
Check JSON, YAML or JSON Lines against a JSON Schema from draft-04 to 2020-12. Errors link to the data line and schema keyword. Runs in your browser, no upload.
- Runs in your browser
- Your data never leaves your browser
- Free · No Sign-Up
Scan with WeChat to share this tool
Examples, details and FAQ Worked examples, how it compares with other tools, and answers to common questions.
Example: the product schema from json-schema.org
The JSON Schema getting started guide builds a product schema step by step. Its last version points to a second file with "$ref": "https://example.com/geographical-location.schema.json". Paste that schema and a product with four mistakes, and the tool stops before checking the data:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"title": "Product",
"type": "object",
"properties": {
"productId": { "type": "integer" },
"productName": { "type": "string" },
"price": { "type": "number", "exclusiveMinimum": 0 },
"tags": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true },
"dimensions": {
"type": "object",
"properties": { "length": { "type": "number" }, "width": { "type": "number" }, "height": { "type": "number" } },
"required": ["length", "width", "height"]
},
"warehouseLocation": { "$ref": "https://example.com/geographical-location.schema.json" }
},
"required": ["productId", "productName", "price"]
}
{
"productId": 1,
"productName": "A green door",
"price": 0,
"tags": ["home", "green", "home"],
"dimensions": { "length": 7.0, "width": 12.0 },
"warehouseLocation": { "latitude": 91, "longitude": -122.4 }
}
The schema cannot be used (Draft 2020-12):
$ref "https://example.com/geographical-location.schema.json" at #/properties/warehouseLocation/$ref cannot be resolved. URLs are not downloaded: paste that schema under Referenced schemas with "$id": "https://example.com/geographical-location.schema.json".
The tool does not download the URL. Paste the guide’s geographical-location schema under Referenced schemas instead:
{
"$id": "https://example.com/geographical-location.schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["latitude", "longitude"],
"properties": {
"latitude": { "type": "number", "minimum": -90, "maximum": 90 },
"longitude": { "type": "number", "minimum": -180, "maximum": 180 }
}
}
Now all four mistakes are reported, in the order they appear in the data, each with its line:
4 errors at 4 locations (Draft 2020-12).
/price (line 4, column 12): must be > 0, but is 0 schema #/properties/price/exclusiveMinimum
/tags (line 5, column 11): items 0 and 2 are equal (uniqueItems) schema #/properties/tags/uniqueItems
/dimensions (line 6, column 17): missing required property "height" schema #/properties/dimensions/required
/warehouseLocation/latitude (line 7, column 38): must be ≤ 90, but is 91 schema https://example.com/geographical-location.schema.json#/properties/latitude/maximum
The error inside the referenced file shows that file’s $id in the schema path, so you know which file to fix.
Example: a schema copied from an OpenAPI 3.0 document
OpenAPI 3.0 schemas often contain nullable and put description or maxLength next to $ref. Pasted into a draft-07 validator, both behave differently from what the author meant. Draft-07 says other keywords in a $ref object must be ignored, and nullable is not a JSON Schema keyword at all:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": { "code": { "type": "string" } },
"type": "object",
"properties": {
"code": { "$ref": "#/definitions/code", "maxLength": 3 },
"nickname": { "type": "string", "nullable": true }
}
}
{ "code": "ABCDEF", "nickname": null }
1 error (Draft 7).
/nickname (line 1, column 33): must be string, but is null schema #/properties/nickname/type
* In Draft 7, keywords next to "$ref" are ignored: "maxLength" at #/properties/code.
* "nullable" at #/properties/nickname is an OpenAPI 3.0 keyword, not JSON Schema, and is ignored. Use "type": ["string", "null"].
Python jsonschema 4.26.0 gives the same answer: code passes (the maxLength is ignored) and nickname: null fails. Plain Ajv, which most browser validators use, reports the opposite on both fields. This tool removes the keywords Ajv applies outside the specification and tells you about each one, so the result matches the specification and the note tells you what to change.
Example: one bad line in a JSON Lines export
Paste one JSON value per line and each line is validated on its own. The result names the line:
{ "type": "object", "required": ["id", "event"], "properties": { "id": { "type": "integer" }, "event": { "enum": ["signup", "login", "logout"] } } }
{"id": 1, "event": "signup"}
{"id": 2, "event": "log-in"}
{"id": 3}
2 of 3 documents have errors (Draft 2020-12).
Document 1 (line 1): valid
Document 2 (line 2)
/event (line 2, column 20): must be one of "signup", "login", "logout" schema #/properties/event/enum
Document 3 (line 3)
(root) (line 3, column 1): missing required property "event" schema #/required
* The data is read as JSON Lines: 3 lines, each validated on its own.
* No $schema: validated as Draft 2020-12. Add "$schema" or pick a draft in the menu.
When the result is “Cannot be determined”
Ajv passes most of the official test suite, but it gets a few constructs wrong. For those inputs the tool gives no valid / invalid result: the status says Cannot be determined, the reasons are listed, and the copied text and JSON say the same ("state": "unknown", "valid": null). A recursive tree schema that uses $dynamicRef, the 2020-12 keyword for extensible recursion, is one case:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$dynamicAnchor": "node",
"type": "object",
"properties": {
"name": { "type": "string" },
"children": { "type": "array", "items": { "$dynamicRef": "#node" } }
}
}
{ "name": "root", "children": [{ "name": 1 }] }
Cannot be determined (Draft 2020-12): this input reaches a case the validator cannot check reliably, so no valid / invalid result is given. Reasons below.
Cannot be determined, because:
- "$dynamicRef" at #/properties/children/items/$dynamicRef: Ajv implements dynamic references only in part and gives wrong results on some official test cases.
If you do not extend the schema from another one, "$ref": "#" means the same here and the tool can check it. The other cases are $recursiveRef whose first target has no "$recursiveAnchor": true, nested $id with relative $ref (Ajv runs out of stack), unevaluatedItems / unevaluatedProperties together with contains, an if without both then and else, or items inside an anyOf / oneOf branch, a meta-schema whose $vocabulary adds or leaves out vocabularies, a property named __proto__ that the data uses, and numbers that JavaScript cannot hold exactly (next section). In JSON Lines and multi-document YAML each document gets its own state: one invalid document makes the result invalid; otherwise one undetermined document makes it undetermined.
How errors are grouped
Ajv, the validator this tool runs, reports every failed branch of a oneOf or anyOf. For a payment that is either a card or a bank account, a card with a two-digit last4 produces five Ajv errors: the two real problems, three complaints from the bank branch, and the summary. This tool shows one error at /payment and opens the closest branch, the one with the fewest errors, not counting a branch whose const discriminator ("method": "bank") already fails. The other branches stay folded. The same works when each branch is a $ref. An if / then failure is shown as the then error with “via then”.
Which draft is used
$schema | Draft |
|---|---|
http://json-schema.org/draft-04/schema# | Draft 4 |
http://json-schema.org/draft-06/schema# | Draft 6 |
http://json-schema.org/draft-07/schema# | Draft 7 |
https://json-schema.org/draft/2019-09/schema | 2019-09 |
https://json-schema.org/draft/2020-12/schema | 2020-12 |
| missing or another URI | 2020-12, with a note |
The tool also reads https://json-schema.org/draft-07/schema and other http / https variants, with a note that some validators do not. Draft-07 array items in a schema without $schema makes the schema invalid under 2020-12; the error says to use prefixItems or pick Draft 7.
Compared with other online validators
We ran the same six inputs through the first results for “json schema validator” on Bing on 2026-10-02: a draft-07 $ref with maxLength next to it, "required": ["constructor"] against {}, nullable with null, 9007199254740993 against "maximum": 9007199254740992, a 2020-12 prefixItems schema, and YAML data.
| Validator | Upload | $ref sibling | constructor | nullable | 2^53 | 2020-12 | YAML |
|---|---|---|---|---|---|---|---|
| jsonschemavalidator.net | yes, schema and data to /api/jsonschema/validate | ignored | fails | fails | passes, no warning | correct | no |
| jsonlint.com | no | applied | passes | passes | passes, no warning | correct | no |
| ZeroTool | no | ignored, note | fails | fails, note | cannot be determined, note | correct | yes |
The correct answers are: ignored, fails, fails, fails. No browser-side validator can get the 2^53 case right, because JSON.parse turns both numbers into 9007199254740992 before validation. This tool names the changed number and gives no verdict for it.
Limits
- The validator is Ajv 8.18 with ajv-formats 3.0.1 and ajv-draft-04 1.0.0. On the required tests of the official JSON Schema Test Suite the tool gives the expected result for 616 of 618 draft-04 tests, 839 of 841 draft-06, 927 of 929 draft-07, 1,230 of 1,261 for 2019-09 and 1,210 of 1,301 for 2020-12, and says “Cannot be determined” for the rest (2, 2, 2, 31 and 91 tests); no test gets a wrong result. The rules look only at the schema and the data, so they also cover some tests Ajv would have passed: every
$dynamicRefschema, for example. $refto a URL is never fetched. Paste the referenced schema, with its$id, under Referenced schemas.- Numbers are read with
JSON.parse. A number that a JavaScript double cannot hold exactly, such as9007199254740993,1.0000000000000001or1e400, gets a note with its line (0.1and1.0are fine). When the schema compares numbers (type,minimum,maximum,multipleOf,const,enum,uniqueItems), that document is “Cannot be determined”. Such a number in the schema, or any such number in YAML data, makes the result “Cannot be determined” in every case.multipleOfis checked on the decimal values, so 19.99 is a multiple of 0.01 and 0.3 is a multiple of 0.1 (dividing the doubles, as Ajv does, says they are not). Duplicate keys keep the last value and get a note. - Line numbers are shown for JSON and JSON Lines. YAML errors show the path only.
- Inputs over 1 MB are checked when you press Validate; files over 20 MB are refused. Validation runs in a Web Worker, so the page keeps responding; Cancel stops a long run. A 6 MB array of 40,000 records took about 2 seconds in our test, with no main-thread task of 50 ms or more while it ran (putting a 6 MB file into the text box is the slow part).
patternis an ECMA-262 regular expression with theuflag.\dmatches only ASCII digits, so Pythonre(where\dalso matches123) can disagree.
Related tools: generate a first schema from a sample with JSON to JSON Schema, check YAML syntax with the YAML Validator, and validate a whole API description with the OpenAPI Validator.
FAQ
Which JSON Schema drafts are supported?
Draft-04, draft-06, draft-07, 2019-09 and 2020-12. The tool reads the draft from $schema. A schema without $schema is checked as 2020-12, the same default as Python jsonschema and Go santhosh-tekuri/jsonschema. Pick a draft in the menu to override $schema; the tool then shows a note that the two differ.
Is my data uploaded?
No. The schema and data are checked by Ajv inside your browser tab, and the tool makes no network requests with them. It also never downloads a schema that a $ref points to: paste that schema under Referenced schemas. Only the draft menu and the Check format switch are saved in your browser.
Does it check format (email, date, uuid)?
Yes, while Check format is on (the default): email, uri, uri-reference, uri-template, date, time, date-time, duration, hostname, ipv4, ipv6, uuid, json-pointer, relative-json-pointer and regex, through ajv-formats. Other formats, such as idn-email or iri, pass and are listed in a note. Turn the switch off to treat format as an annotation, which is the default of the 2020-12 specification and of Python jsonschema.
Why does my schema pass here and fail in another validator?
Usually the draft, format checking or a keyword the draft does not have. The notes under the result list what this tool ignored: unknown keywords (with a suggestion for typos), keywords next to $ref in draft 4–7, nullable from OpenAPI 3.0, and formats it does not check. Another cause is a number such as 9007199254740993 that JavaScript cannot hold exactly; when the schema compares numbers, this tool says "Cannot be determined" instead of giving a result.
Can I validate a JSON array or many records at once?
Yes. Any JSON value can be the root, including an array. For many records, paste JSON Lines (one JSON value per line) or YAML documents separated by ---; each document is validated on its own and the result lists the ones with errors.