Claude 'Schema is too complex' 400: strict tool limits vs Sume
Claude caps strict tools at 20, optional parameters at 24 and union parameters at 16 per request. Sume checks 10 levels and 5000 properties at submit.

Claude returns a 400 with "Schema is too complex for compilation" when strict tools and JSON outputs exceed its limits: 20 strict tools, 24 optional parameters and 16 union-type parameters per request. Sume uses different limits, a nesting depth of 10 and 5000 properties, and it checks them before anything runs, so an oversized schema returns 400 output_schema_invalid and costs nothing.
Claude's numbers are from its structured outputs page. Sume's are from Structured output and Errors and spend.
What are Claude's complexity limits?
The page lists three explicit per-request limits and says compiled grammar size also matters, with limits that interact non-linearly. Compilation has a 180-second timeout, and the first use of a schema adds latency because the grammar is compiled; compiled grammars are cached for 24 hours.
| Limit | Value |
|---|---|
| Strict tools (strict: true) | 20 |
| Optional parameters across all strict schemas | 24 |
| Parameters using anyOf or a type array with null | 16 |
| Compilation timeout | 180 seconds |
| Error when exceeded | 400 Schema is too complex for compilation |
What are Sume's limits, and when do they fire?
Sume's limits are fixed numbers on the schema document, not on a tool count. The docs list a nesting depth of 10 levels (violation max_depth), 5000 total properties across the whole document (max_properties) and 1000 values per enum (max_enum_values). A violation is returned in details.violations[] with a path, a rule and a message, one entry per problem.
Because the check runs at create, a rejected schema never starts a run and never charges the wallet. There is also no first-request compile step to wait on. Do not treat that as a promise about every schema that passes: a schema that validates can still fail later as output_schema_unsatisfied if it demands media the Format never makes.
How do the two compare side by side?
The unit is the main difference. Claude counts how many strict tools and optional or union parameters you send; Sume counts depth and total properties in one schema.
| Question | Claude | Sume |
|---|---|---|
| Where is it checked | At request time, with a 400 | At create, with 400 output_schema_invalid |
| Depth limit | Not stated as a number on the page | 10 levels |
| Property limit | 24 optional, per request | 5000 in the document |
| Optional fields | Counted against a limit | Every field must be listed in required; model optional as a null union |
| Recursion | Not supported | Through a named $defs entry, not $ref: "#" |
How do I shrink a schema that Claude rejected?
Claude's page suggests four fixes: mark only critical tools as strict, make parameters required instead of optional, flatten nested structures, and split the work across requests. Moving the same schema to Sume has one extra rule: every object needs additionalProperties: false, and strict: false does not relax the subset.
If your Sume schema is rejected, read every entry in details.violations[] at once instead of fixing one and resubmitting. The post Fix output_schema_invalid violations walks through them.
Sources
Related posts
More in Formats
- Claude structured output refusal or max_tokens: what Sume does
Claude can return a 200 that does not match your schema on refusal or max_tokens. Sume reports a failed projection as output_error on the receipt instead.
- Sume Format API staging: api.dev.sume.com and the 401 on a wrong host
Sume serves the Format API on api.sume.com and api.dev.sume.com with the same routes. A key works only on its own host; the other answers 401 unauthorized.
- Format bulk queue: no queue webhook, no cancel-queue endpoint
A Sume bulk queue has no webhook and no cancel call. Poll the queue, put webhooks on items, and cancel the child runs one by one with their run ids.
- Format Contents API: read the whole package, commit many files at once
Read a Sume Format package with ?recursive=1 and write several files as one commit and one version bump. A change set, not the package; deletes stay separate.
Written by Sume