Figures on this page were verified 18 October 2026 against the providers' own documentation. Pricing, context windows and rate limits change without notice, so confirm any number against the provider before you rely on it. Tell us if something here is out of date.
A strict-mode rejection means your schema uses a JSON Schema feature that grammar-constrained sampling cannot compile, and the fix is almost always removing a constraint, not rewording the tool. Setting strict: true makes the provider compile your schema into a grammar that restricts which tokens the model may emit. Anything that grammar cannot express is refused up front with a 400, instead of being silently ignored.
Why strict mode is pickier than normal tool use
Without strict mode, your schema is just guidance the model reads. Violations are possible, which is why arguments sometimes arrive wrong. With strict: true, the schema becomes a hard constraint on sampling, so the provider must be able to turn every part of it into a grammar. Features that cannot be compiled are rejected rather than approximated.
That trade is worth making. On Anthropic, strict mode guarantees tool inputs match the schema, so you stop validating and retrying. On OpenAI, setting strict to true makes calls reliably adhere to the schema instead of being best effort. The cost is a narrower subset of JSON Schema.
What Anthropic’s strict mode does not support
| Feature | Status | What to do instead |
|---|---|---|
minimum, maximum, multipleOf | Not supported | Validate in your own code, state the range in the description |
minLength, maxLength | Not supported | Validate in your own code, state the limit in the description |
| Recursive schemas | Not supported | Flatten to a fixed depth |
External $ref | Not supported | Inline the definition or use a local $defs |
additionalProperties other than false | Not supported | Set it to false on every object |
Array minItems above 1 | Only 0 or 1 allowed | Check the count after the call |
Complex types inside enum | Not supported | Use strings, numbers, booleans or null only |
allOf combined with $ref | Not supported | Merge the properties into one object |
String format | Limited list only | Use date-time, time, date, duration, email, hostname, uri, ipv4, ipv6 or uuid |
The pattern across that table is consistent: numeric and length bounds are out, because they are validation rather than structure. Move them into your own code and keep them in the property description so the model still sees the intent.
Regex patterns: supported, but only a subset
The pattern keyword works, with limits. Character classes, groups, *, +, ? and simple {n,m} quantifiers are fine. Backreferences, lookahead, lookbehind, and word boundaries such as b are not. A pattern like ^(?=.*[A-Z]).{8,}$ that uses lookahead will be rejected even though it is valid regex in every other context.
The limits that bite on larger tool sets
Some rejections are not about any single feature but about the total. Anthropic applies per-request ceilings across every strict schema combined:
| Limit | Value |
|---|---|
| Strict tools per request | 20 (non-strict tools do not count) |
| Optional parameters across all strict schemas | 24 |
Parameters using union types (anyOf or type arrays) | 16 |
Exceed those and you get a 400 with the message “Schema is too complex for compilation.” The counts are cumulative across the whole request, so twenty small tools can trip the optional-parameter ceiling even though no individual tool is complex. Internal grammar-size limits also apply and are not published, and compilation has a 180-second timeout.
OpenAI’s strict mode has different rules
OpenAI enforces structure rather than banning keywords. With strict: true, every object in parameters must set additionalProperties to false, and every field in properties must appear in required. That second rule surprises people, because it means there is no such thing as an omitted optional field. Optional fields are expressed by allowing null as a type.
{
"type": "function",
"name": "search_flights",
"strict": true,
"parameters": {
"type": "object",
"properties": {
"destination": {"type": "string"},
"departure_date": {"type": "string"},
"passengers": {"type": ["integer", "null"]} // optional, expressed as nullable
},
"required": ["destination", "departure_date", "passengers"], // ALL fields listed
"additionalProperties": false
}
}If you send strict: true with a schema that breaks those rules, the request is rejected. If you omit strict, the Responses API tries to normalise the schema and falls back to non-strict when it cannot, showing strict: false on the tool. Chat Completions is non-strict by default. That silent fallback is worth knowing about: a schema you assumed was strictly enforced may not have been.
A schema body that works on both
If you support more than one provider, write the schema body to the intersection once and keep it boring. The envelope differs: Anthropic calls the schema input_schema and puts strict at the top level of the tool, while OpenAI calls it parameters. The rules for the body are the same: every object has additionalProperties: false, every property is listed in required, optional values are nullable, enums hold only scalars, and ranges and lengths live in the description and your own validation.
{
"name": "set_quantity",
"description": "Set the quantity of an item in the cart. quantity must be a whole number from 1 to 99.",
"strict": true,
"input_schema": {
"type": "object",
"properties": {
"item_id": {"type": "string"},
"quantity": {"type": "integer"},
"gift_note": {"type": ["string", "null"]}
},
"required": ["item_id", "quantity", "gift_note"],
"additionalProperties": false
}
}
# then enforce 1..99 in your own handler:
if not 1 <= args["quantity"] <= 99:
return {"is_error": True, "content": "quantity must be between 1 and 99"}Do not put sensitive values in the schema
One non-obvious point from Anthropic’s data-retention notes: compiled schemas are cached for up to 24 hours since last use, and that cache does not receive the same protections as prompts and responses. Keep personal or regulated data out of property names, enum values, const values, and pattern expressions.
Related errors
If arguments are wrong without any strict-mode rejection, see tool call arguments that will not parse. If a request is rejected for exceeding a count of tool calls rather than schema complexity, see tool call limits and pause_turn. The full map is in the LLM API error reference.
Frequently asked questions
Why does strict mode reject schemas that work without it?
Strict mode compiles your schema into a grammar that constrains sampling, so anything the grammar cannot express is refused with a 400 instead of ignored. Without strict mode the schema is only guidance the model reads.
Which JSON Schema features does Anthropic strict mode not support?
Numeric bounds such as minimum and maximum, string length bounds, recursive schemas, external refs, additionalProperties other than false, and array minItems above 1. Validate those in your own code and state them in the description.
What are the strict mode limits per request?
On Anthropic, 20 strict tools, 24 optional parameters and 16 union-typed parameters across the whole request. Exceeding them returns a 400 with the message Schema is too complex for compilation.



