JSON Schema Validator

Drafts 4 to 7 check format by default. 2019-09 and 2020-12 treat it as an annotation.
Each example has a few deliberate mistakes so you can see what the errors look like.

Checks as you type. Ctrl+Enter (Cmd+Enter on a Mac) validates right away. Click any path in the results to jump to that spot.

By Cobra · Last updated

Drafts 4 through 2020-12, picked from $schema

Validation runs on @hyperjump/json-schema 1.18.0, an open-source validator by Jason Desrosiers (Hyperjump) that is listed on json-schema.org's tools page. A copy is served from this site with its MIT license. It covers the newer keywords too, including $dynamicRef, unevaluatedProperties, unevaluatedItems, dependentSchemas and prefixItems.

The draft comes from your $schema value, so http://json-schema.org/draft-07/schema# runs as draft 7 even if the selector says something else. The page tells you when that happens. A schema without $schema uses the selector, and Auto means 2020-12. Your schema is also checked against its draft's meta-schema first, so a typo like "type": "objekt" is reported as a schema error instead of silently passing.

Test suite results for this validator

We ran the official JSON Schema Test Suite (commit 5571928, October 13, 2026) against the exact json-schema-engine.js file this page loads, through the same function the Validate button calls. Remote schemas the suite needs were registered locally, since this page never fetches. Required tests are the core of each spec. Optional tests cover behavior the spec leaves open, and format tests check format as an assertion.

DraftRequired testsOptional testsFormat tests
Draft 4610 / 618 (98.7%)97 / 100 (97.0%)291 / 291 (100.0%)
Draft 6833 / 841 (99.0%)102 / 106 (96.2%)414 / 414 (100.0%)
Draft 7921 / 929 (99.1%)108 / 118 (91.5%)803 / 809 (99.3%)
Draft 2019-091,257 / 1,261 (99.7%)134 / 158 (84.8%)884 / 890 (99.3%)
Draft 2020-121,298 / 1,302 (99.7%)140 / 162 (86.4%)884 / 890 (99.3%)

What still fails in the required tests: a schema whose $id is a file: URI (4 tests per draft; the library refuses to register those), a $ref with a sibling $id in drafts 4, 6 and 7 (2 tests), and a base URI change inside a subschema in drafts 4, 6 and 7 (2 tests). In format tests, leap-second times such as 23:59:60Z are rejected (6 tests in draft 7 and later). In 2019-09 and 2020-12, most optional failures (14 of 24, and 14 of 22) come from the old dependencies keyword, which those drafts replaced with dependentRequired and dependentSchemas.

Reading an error: instance path and schema path

Every error shows two JSON Pointers. The first, in code, is where the problem is in your data. The second, in brackets, is the keyword in your schema that failed. With the schema above and the data {"name":"","age":-1,"nickname":"A"} you get four errors:

Fix them from the top. A missing required property often explains the errors below it. Click either path in the results and the validator selects that spot in the text box, which helps a lot in long files.

Worked example: checking an API response

Pick API response with $ref and $defs in the example menu above. The schema describes an order: an id like ord_7f3k9q2m, a status from a fixed list, a three-letter currency, and an items array where every line item is checked against one shared definition in $defs/lineItem. The response has five mistakes, and the validator reports each one:

  1. /status must be one of ["pending","paid","shipped","refunded"]. The value is "Paid". enum compares exactly, so case matters. Fix the data, or list both spellings if your API really sends both.
  2. /currency must match pattern "^[A-Z]{3}$". "usd" is lowercase. Patterns are case sensitive and JSON Schema has no case-insensitive flag, so write the character class you need, such as ^[A-Za-z]{3}$.
  3. /items/1/qty must be integer, got string. The second item has "qty": "1". Quoted numbers are strings in JSON. This one is very common when data passes through a form or a CSV first.
  4. /items/2/price must be > 0, got 0. The schema uses "exclusiveMinimum": 0, so zero itself is not allowed. Use "minimum": 0 if free items are fine.
  5. /items/2/color is not allowed. lineItem sets "additionalProperties": false, so any key that is not listed is rejected. Add color to properties if it is a real field.

Notice the schema paths for items 3 to 5 start with /$defs/lineItem. The error happened inside the referenced definition, so that is where you edit the rule, and the fix applies to every item at once. The /items/1 and /items/2 parts of the instance path are array indexes, counted from zero.

Common error messages and what to do

MessageWhat it usually meansFix
must be integer, got stringA number arrived in quotes, like "42".Send a real number, or allow both with "type": ["integer", "string"] plus a pattern.
must be integer, got numberThe value has a fraction, like 36.5.Use "type": "number" if decimals are valid.
missing required property: xThe key is absent. A key set to null counts as present.Add the key, or remove it from required.
is not allowed ("additionalProperties" is false here)A key that is not listed in properties or matched by patternProperties. Often a typo in the data or the schema.Add the key to properties, or fix its spelling.
is not allowed ("unevaluatedProperties" is false here)Same idea, but it also sees keys defined inside allOf, $ref and if/then.Use this instead of additionalProperties when you combine schemas.
must be one of [...]The value is not in enum. The comparison is exact: case, type and whitespace all count.Match one listed value exactly.
must match pattern "..."The regex did not match. Patterns are not anchored unless you add ^ and $.Test the regex on its own and add anchors if the whole value must match.
is not a valid email (or date-time, uri, ...)A format check failed. Only shown when format is checked for your draft or setting.Fix the value, or set Format checks to Never if you only want annotations.
must match at least one subschema in anyOfNone of the options matched. The nested lines show why each option failed.Read the option you meant to match and fix that one.
matches more than one subschema in oneOfThe options overlap, so the data matched two of them. Common with number and integer, or objects without required.Make the options exclusive, for example with required or const on a type field, or use anyOf.
has "a", so it also needs "b"A dependentRequired (or draft 4 to 7 dependencies) rule.Send both keys together, or neither.
The schema itself has a problemThe schema does not match its draft's meta-schema, like "type": "objekt" or "required": "name" instead of an array.Click the path to see the bad keyword and check its spelling and value type.

What changed between drafts

Most schemas work the same in every draft, but these differences cause real bugs when a schema written for one draft is read as another. That is why the $schema line matters.

TopicDraft 4Drafts 6 and 72019-092020-12
Schema IDid$id$id, plus $anchor$id, $anchor
Reusable partsdefinitionsdefinitions$defs$defs
Keywords next to $refIgnoredIgnoredAppliedApplied
Exclusive limitsexclusiveMinimum: true next to minimumexclusiveMinimum: 5 (a number)A numberA number
Tuplesitems: [...] + additionalItemsSameSameprefixItems: [...] + items
ConditionalsNoneif / then / else from draft 7YesYes
Property dependenciesdependenciesdependenciesdependentRequired, dependentSchemasSame as 2019-09
Closing combined schemasNot possibleNot possibleunevaluatedProperties, unevaluatedItemsSame
New keywords(baseline)const, contains, propertyNames, true/false schemas (6); $comment, readOnly, writeOnly (7)minContains, maxContains, $recursiveRef$dynamicRef replaces $recursiveRef
format (this page's default)CheckedCheckedAnnotation onlyAnnotation only
$schema valuehttp://json-schema.org/draft-04/schema#http://json-schema.org/draft-07/schema# (or draft-06)https://json-schema.org/draft/2019-09/schemahttps://json-schema.org/draft/2020-12/schema

The array form of items is the change that bites most often. In 2020-12, "items": [{...}, {...}] is a schema error, and the same tuple is written with prefixItems. The Tuple with prefixItems example above shows the 2020-12 way.

Large files

Validation runs in your browser tab, so the limit is your device's memory. In our test on October 20, 2026, in desktop Chrome, a 5 MB file with 50,000 records took about 0.6 seconds from click to result, and a 10 MB file with 100,000 records about 2 seconds. Phones are slower. Above about 400 KB, the page stops checking on every keystroke and waits for the Validate button, so typing stays smooth. If there are thousands of errors, the first 200 are listed with a button to show the rest. Usually they are the same mistake repeated, so fix the first one and check again.

Where this validator stops

JSON Schema mistakes that pass silently

Validate JSON Schema in JavaScript, Python and Go

The same schema and the bad instance {"age": -1} in each language. Every snippet reports the missing email and the negative age with their paths.

JavaScript: Ajv with the 2020-12 build

import Ajv2020 from "ajv/dist/2020.js"; // npm i ajv ajv-formats
import addFormats from "ajv-formats";

const schema = {
  $schema: "https://json-schema.org/draft/2020-12/schema",
  type: "object",
  required: ["email"],
  properties: { email: { type: "string", format: "email" }, age: { type: "integer", minimum: 0 } },
};

const ajv = new Ajv2020({ allErrors: true });
addFormats(ajv); // format is only checked when you add this
const validate = ajv.compile(schema);
if (!validate({ age: -1 })) {
  for (const e of validate.errors) console.log(e.instancePath || "/", e.message);
}

Python: jsonschema

from jsonschema import validators  # pip install jsonschema

schema = {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "type": "object",
    "required": ["email"],
    "properties": {"email": {"type": "string", "format": "email"},
                   "age": {"type": "integer", "minimum": 0}},
}

cls = validators.validator_for(schema)  # picks the draft from $schema
cls.check_schema(schema)
v = cls(schema, format_checker=cls.FORMAT_CHECKER)
for err in v.iter_errors({"age": -1}):
    print(err.json_path, err.message)

Go: github.com/santhosh-tekuri/jsonschema/v6

package main

import (
	"fmt"
	"strings"

	"github.com/santhosh-tekuri/jsonschema/v6" // go get github.com/santhosh-tekuri/jsonschema/v6
)

const schemaJSON = `{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["email"],
  "properties": {"age": {"type": "integer", "minimum": 0}}
}`

func main() {
	schemaDoc, _ := jsonschema.UnmarshalJSON(strings.NewReader(schemaJSON))
	c := jsonschema.NewCompiler()
	if err := c.AddResource("schema.json", schemaDoc); err != nil {
		panic(err)
	}
	sch, err := c.Compile("schema.json")
	if err != nil {
		panic(err)
	}
	inst, _ := jsonschema.UnmarshalJSON(strings.NewReader(`{"age": -1}`))
	fmt.Println(sch.Validate(inst)) // nil when valid, otherwise every error with its path
}

Each snippet was run on October 14, 2026 with Ajv 8.20.0 with ajv-formats 3.0.1, jsonschema 4.26.0 and santhosh-tekuri/jsonschema v6.0.3.

JSON Schema specs and test suite

FAQ

Does validation upload my JSON?

No. The schema and the instance stay in your browser. The validator is a local copy of the open-source @hyperjump/json-schema library, and this page never fetches anything while it validates, not even a remote $ref.

Which JSON Schema drafts are supported?

Drafts 4, 6, 7, 2019-09 and 2020-12. If your schema has a $schema keyword, that draft is used, as the spec requires. If it has none, the draft selector decides, and Auto falls back to 2020-12. Draft 3 and older are not supported.

How compliant is this validator?

We ran the official JSON Schema Test Suite against the exact script this page loads. Required tests pass at 98.7% for draft 4, 99.0% for draft 6, 99.1% for draft 7, and 99.7% for both 2019-09 and 2020-12. The table on this page lists every number, including the optional and format tests, and what fails.

Why did my $ref fail?

References inside the same document work, including $defs, definitions, $anchor and embedded $id. References to other files or URLs are not fetched. Copy the referenced schema into $defs and point $ref at it.

Is format checked?

By default it follows each draft: drafts 4, 6 and 7 check format, while 2019-09 and 2020-12 treat it as an annotation only. Use the format setting to always check it or never check it.

Why does data with extra fields still pass?

JSON Schema allows extra properties by default. Add additionalProperties: false to the object schema to reject unknown keys, or unevaluatedProperties: false in 2019-09 and later when you combine schemas with allOf.

Which draft should I use for a new schema?

Use 2020-12 unless a tool you depend on only reads an older draft. OpenAPI 3.1 uses 2020-12, while OpenAPI 3.0 uses its own extended subset of an older draft, which this page does not support. Whatever you pick, put it in $schema so every validator reads the schema the same way.

How do I find an error in a long file?

Click the path at the start of any error and the validator selects that value in the instance box. Click the schema path to select the rule that failed. If the JSON itself is broken, the message gives the line and column and a Show me button jumps there.

Can I generate a schema from sample data?

Yes. Use the JSON Schema generator to draft one from an example, then tighten required fields and constraints by hand and test it here.