Skip to content
AZ Tools

JSON Schema Validator

Paste a schema on the left and a document on the right, and this tells you whether the document validates and, when it does not, exactly where and why. Each error is one row: the JSON Pointer into your document, the keyword that failed, the place in the schema that keyword came from, the offending value, and — the part a bare pointer never gives you — the line of the pasted document the pointer lands on. Rows are ordered the way you would read the file, so the first row is the first problem you would scroll to. The report that earns the tool is anyOf and oneOf. Most validators flatten those: a value that misses three branches produces every complaint from all three, in one undifferentiated list, and the useful sentence is buried. Here the failure stays one row with the branches underneath it, each named by what it asks for, each carrying its own errors, and the branch that came closest — fewest problems — marked, because that is almost always the branch you meant. A oneOf that matches two branches is reported as its own failure and names the branches, which is the other half of the keyword people forget. The draft matters more than most people expect, so the tool shows which one it used and how it chose: the $schema in your schema when there is one, otherwise the draft you pick. Under draft 4, 1.0 is not an integer and exclusiveMinimum is a boolean modifying minimum; from draft 6 onwards 1.0 is an integer and exclusiveMinimum carries the bound. In draft 7 and earlier, every keyword written beside a $ref is ignored — a schema that looks like it also checks minLength does not. Other answers that surprise people are the same in every draft: required is about presence, so a property set to null satisfies it; minLength counts code points, so an emoji is one and a decomposed accent is two; 0.3 is not a multiple of 0.1 in binary floating point; and two objects that differ only in key order are the same value, while two arrays in a different order are not. A schema can also be broken rather than strict, and that is a different answer. A misspelt type name, a required that is not an array, a pattern that will not compile, a $ref that resolves to nothing — each is reported as a fault in the schema, with a pointer to the spot, instead of being silently turned into a passing or failing document. What it cannot tell you: nothing is fetched over the network, so a $ref to a URL is unresolvable here and has to be inlined into $defs; unevaluatedProperties, unevaluatedItems and $dynamicRef are flagged and skipped rather than guessed at; integers past 2^53 are read as doubles, which a server-side validator does not do; and patterns run on the browser regular-expression engine, which the specification asks for but which differs from a Python or Go validator at the edges. Everything happens in the page — neither the schema nor the document leaves your machine.

format is an annotation by default. Turn this on to make it fail.

A schema that declares $schema picks its own draft; this setting is only used when it does not.

Result

Invalid

Errors

7

Draft

2020-12

Document

12 lines, 169 bytes

7 errors2020-12 · chosen by $schema
the whole documentline 1additionalProperties

The schema allows no other properties, and these are here: "debug"

debug (line 11)

value: {"name":"","version":"2.1","server":{"host":"0.0.0.0","port":99999,"tls":"yes"},"workers":…

schema: /additionalProperties

/nameline 2minLength

The string is 0 code points long, and the minimum is 1

value: ""

schema: /properties/name/minLength

/versionline 3pattern

"2.1" does not match the pattern ^\d+\.\d+\.\d+$

value: "2.1"

schema: /properties/version/pattern

/server/portline 6maximum

99999 is above the maximum of 65535

value: 99999

schema: /properties/server/properties/port/maximum

/server/tlsline 7type

"yes" is a string, and the schema asks for boolean

value: "yes"

schema: /properties/server/properties/tls/type

/workersline 9anyOf

None of the 2 anyOf branches accepts this value

value: 0

schema: /properties/workers/anyOf

Branch by branch

Branch 1 type: integer 1 problemsclosest match

  • /workers — 0 is below the minimum of 1

Branch 2 const: "auto" 1 problems

  • /workers — 0 is not the constant "auto"
/tagsline 10uniqueItems

The items at index 0 and index 1 are the same value: "a"

value: ["a","a"]

schema: /properties/tags/uniqueItems

Everything runs in this page. Neither the schema nor the document is uploaded.

How to use

  1. Paste your schema into the first box and the document you want to check into the second. Both boxes keep what you typed, so the page can be closed and reopened.
  2. Read the verdict tiles: valid or invalid, how many errors, which draft was used, and how big the document is. The draft line also says whether it came from $schema or from the selector.
  3. Work down the error rows. Each names the JSON Pointer, the line in your document, the failing keyword, the value that was there, and the location inside the schema, so you can fix either side.
  4. Open an anyOf or oneOf row and read the branches. The branch marked as the closest match is the one that failed on the fewest things, which is usually the one you were aiming for.
  5. Turn on "Assert format" when you want format to fail rather than annotate — that is off by default because the specification says format is an annotation, and most validators leave it that way.

Frequently asked questions

Why does my document pass when I expected it to fail?
Almost always because the schema says less than it looks like it says. JSON Schema ignores keywords it does not know, so "require" instead of "required", "minlength" instead of "minLength", or a 2020-12 keyword in a draft-07 schema is not an error — it is an annotation that quietly does nothing. Objects also accept extra properties unless additionalProperties or unevaluatedProperties says otherwise, arrays accept anything unless items or prefixItems constrains them, and format only annotates unless you turn assertion on. Check the draft shown in the tiles too: a keyword can exist in one draft and not another, and this tool ignores keywords the chosen draft never had.
Is 1.0 an integer?
In draft 6 and later, yes: the specification defines "integer" by the value, so 1.0 and 1.0e2 are integers and 1.5 is not. In draft 4, no: a number written with a fractional part is a float and fails "type": "integer". This tool keeps the literal spelling of every number while parsing, which is why it can tell 1 from 1.0 at all — JSON.parse gives both the same value. If you are validating with an old library against a draft-04 schema, that difference is a real source of production surprises, and switching the draft selector here reproduces it.
Why is 0.3 not a multiple of 0.1?
Because neither number is exact in binary floating point. 0.3 divided by 0.1 is 2.9999999999999996, not 3, and the reference validators test exactly that quotient, so the document is rejected. The same schema written as "multipleOf": 1 with the value scaled to 3 passes. This is not a quirk of this tool: python-jsonschema, ajv and the rest all behave this way for decimal multipleOf, which is why a schema meant to say "two decimal places" is better written as a pattern or an integer count of cents.
How do I read the JSON Pointer in an error?
A pointer is a path of slash-separated tokens from the root of the document: /server/port is the port member of the server object, and /tags/2 is the third element of tags, because indexes start at zero. An empty pointer means the document as a whole, which is why errors from required, additionalProperties and uniqueItems point at the containing object or array rather than at the member — the missing property has no place of its own. A literal / inside a property name is written ~1 and a literal ~ is written ~0. The line number next to each pointer is this tool resolving that path in the exact text you pasted.
Why does anyOf produce so many errors in other validators?
Because a failed anyOf really did fail every branch, and the errors are all technically true. A validator with no opinion prints all of them side by side, so a two-branch union of a string and an object turns into a list where "is not of type string" sits next to a missing-property complaint about an object you never intended. Grouping them by branch restores the structure the schema had, and picking the branch with the fewest failures gets you to the intended one nearly every time. It is a heuristic, not a proof: when two branches fail on one thing each, the tool marks the first, and the schema itself cannot say which you meant.
Can it follow a $ref to another file or a URL?
No, and that is deliberate: nothing here reaches the network, so a $ref to https://example.com/user.json, or to a sibling file such as common.json#/$defs/id, cannot be resolved and is reported as a fault in the schema rather than quietly ignored. Refs inside the pasted document work in full — #/$defs/name, a plain #, a recursive reference to the root, an $anchor, and an $id that another ref names. To check a schema that is split across files, bundle it first: paste the referenced definitions into $defs and repoint the refs, which is also what most tooling does before shipping a schema.

Related tools