LLM JSON Schema Strict Mode Checker

Paste a JSON schema, a tool definition or an output_config format block. Get the things a constrained decoder rejects outright, separated from the things it merely ignores.

Paste below, or drop a file anywhere on this panel

Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.

The answer appears here

Paste on the left and press Check. Nothing leaves this tab.

Examples

Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.

The two most common rejections

additionalProperties: false is required on every object, and every property must appear in required

{
  "type": "object",
  "properties": {
    "city": { "type": "string", "description": "City name." },
    "units": { "type": "string", "description": "Units." }
  },
  "required": ["city"]
}

A bound that is refused rather than ignored

The same keyword is silently dropped in a non-strict request and rejects the request outright in a strict one

{
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "days": { "type": "integer", "description": "How many days.", "maximum": 14 }
  },
  "required": ["days"]
}

Recursion cannot be compiled

A self-reference has no bounded shape, so there is no grammar to build from it

{
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "name": { "type": "string", "description": "This node." },
    "child": { "$ref": "#" }
  },
  "required": ["name", "child"]
}

Common mistakes

These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.

  1. Putting `additionalProperties: false` on the root only

    Strict mode requires it on every object, including ones nested inside `properties`, `items` and each `anyOf` branch. A schema with it at the top looks compliant and is rejected.

    Instead:Add it to each object schema. This is the single most common rejection.

  2. Leaving optional properties out of `required`

    Strict mode has no concept of an optional property, so a property missing from `required` is a schema error rather than an optional field.

    Instead:List every property in `required`, and express optionality by giving the value an `anyOf` with a null branch.

  3. Keeping `minimum`, `pattern` or `maxLength` because they are harmless

    They are harmless in a non-strict request, where they are ignored. In a strict one they are refused, so the same schema works in one mode and fails in the other.

    Instead:Remove them and enforce after parsing. Put the constraint in the description, which does influence generation.

The same schema is accepted in one mode and rejected in the other

Without strict mode, unsupported keywords are ignored and your tool receives values that violate them. With strict mode, the same keywords are rejected before the request runs. Knowing which mode you are in decides which failure you get.

additionalProperties: false on every object, not just the root

This is the most common rejection, and the reason is that the default is true and leaving it out is invisible. It applies to nested objects, to objects inside items, and to every branch of an anyOf. A schema with it only at the top level looks compliant and is not.

Every property must be in required

Strict mode has no concept of an optional property. Optionality is expressed by making the value nullable instead: keep the property in required and give it an anyOf with a null branch, so the model can decline to fill it in without omitting the key. This is unintuitive enough that it is the second most common rejection.

Numeric and string bounds are refused, not ignored

minimum, maximum, multipleOf, minLength, maxLength, pattern, minItems and the rest express constraints a grammar cannot enforce during generation, so a constrained decoder refuses to compile the schema. In a non-strict request the same keywords are accepted and simply not applied. Put the constraint in the property's description as well; that part does influence what gets generated.

Recursion cannot be compiled at all

A self-reference has no bounded shape, so there is no grammar to build. Flatten to a fixed depth, or take the nested structure as a JSON string and parse it yourself. A string field whose description gives the expected shape works well and costs one parse.

Only ten string formats are understood

date-time, time, date, duration, email, hostname, uri, ipv4, ipv6 and uuid. Anything else is either rejected or ignored depending on the mode, and neither is what you wanted. Describe the shape in the description and give an example instead.

A new schema pays a compilation cost on its first request

The schema is turned into a grammar once and cached for about a day. A workload that builds a fresh schema per request never hits that cache and pays the latency every time, which is a good reason to keep schemas stable rather than generating them.

What this cannot see

Which exact subset your provider and model enforce today. The rules checked here are the widely documented ones, and a provider may be stricter or more forgiving in places. It also cannot tell you whether the schema describes what your code actually accepts: a schema can be perfectly strict-compliant and still be wrong about your tool. It reads the pasted document in your browser and calls nothing.