JSON Schema oneOf not supported in strict mode: fix the violations
Sume rejects an output_schema outside the OpenAI strict-mode subset with 400 output_schema_invalid. Read each violation's rule, then port oneOf and nullable.

JSON Schema oneOf is not supported in the strict-mode subset Sume enforces for output_schema, so a Format run whose schema uses it is refused at submit with 400 output_schema_invalid. Replace oneOf with anyOf, then work through details.violations[]: each entry names a path and a stable rule, one 400 lists every problem, and nothing runs or is charged until the schema passes.
The rule tokens and porting fixes below come from the Supported schemas section of Sume's Structured output page, read on 2026-09-26. The accepted keyword list itself is in Sume Format structured output.
How do I read details.violations[]?
Each entry is { path, rule, message }. Every problem is reported, not just the first, so one 400 is enough to fix the schema.
pathis a JSON-Pointer-style location, such as#/properties/scenes/items/properties/clip.ruleis a stable lowercase token that is safe toswitchon.messageis written for a human and may change.
What does each violation rule mean?
Each rule token flags one part of the subset. The example after the table is the docs' fix for root_must_be_object on a top-level array.
| `rule` | What it means |
|---|---|
root_must_be_object | The root is missing, is not an object, or its type is not exactly "object". Even ["object", "null"] is rejected. |
not_an_object | A schema node is not a JSON object. |
missing_type | A node has no type, $ref, or anyOf. A bare { "description": "…" } counts. |
unsupported_type | A type outside string, number, integer, boolean, object, array, null. |
unsupported_keyword | A keyword off the allowlist. |
additional_properties_false | An object node without additionalProperties: false, including inside items and $defs. |
required_completeness | A declared property missing from required, or a required entry with no matching property. |
missing_items | An array node with no items. |
unsupported_ref | A $ref that is neither #/$defs/<name> nor SumeMediaFile#, or one naming a definition that does not exist. |
invalid_defs | $defs is present but is not an object of named schemas. |
max_depth | More than 10 levels of nesting. |
max_properties | More than 5000 properties, counted across the whole document. |
max_enum_values | More than 1000 values in one enum. |
max_string_length | More than 120,000 characters, summed over every property name, key, and string value. |
// rejected
{ "type": "array", "items": { "type": "string" } }
// accepted
{
"type": "object",
"additionalProperties": false,
"required": ["captions"],
"properties": { "captions": { "type": "array", "items": { "type": "string" } } }
}How do I port a schema that uses oneOf, allOf, or nullable?
Each of these is an unsupported_keyword. Schemas ported from OpenAPI reach for oneOf by reflex, and the docs give a replacement for every common case:
oneOf: useanyOf. OnlyanyOfis on the allowlist.allOf: flatten the branches into one object.not,if/then/else,dependentRequired,dependentSchemas: not expressible. Model the alternatives asanyOf, or validate on your side after readingoutput.nullable: true: use a nullable union,"type": ["string", "null"]. The same union replaces an optional property, because every declared property must be inrequired.patternProperties,propertyNames,unevaluatedProperties,additionalItems: declare the properties you want;additionalProperties: falsecovers the rest.
Why do constraints next to $ref or anyOf do nothing?
$ref and anyOf each short-circuit the node they sit on. Sibling keywords are checked against the allowlist but otherwise carry no meaning, so a constraint written beside a $ref has no effect. Put constraints inside the anyOf branches, or inside the $defs entry the $ref points at.
Where must $defs live, and can a schema recurse?
Only two $ref targets resolve: #/$defs/*, declared at the root of the schema document, and SumeMediaFile#. That rules out several habits from other tools:
- External refs fail: a URL, a sibling document, or an OpenAPI-style
#/components/...path. - A
$defsblock nested inside a sub-schema fails, because its#/$defs/*target has no matching root entry. $ref: "#"is rejected. OpenAI's strict mode permits root recursion that way; Sume does not.- Recursion through a named definition is fine: a
$defsentry may$refitself, and it does not consume the depth limit, which counts literal nesting in the document.
Why does a big schema hit max_string_length?
The 120,000-character limit is a document-wide budget, not a per-field cap. Long description annotations on a large schema can exhaust it even when no single string is remarkable, so trim annotations before you cut fields.
Can strict: false get a schema past the violations?
No. strict: false is accepted and stored, and it changes nothing about the subset. There is no JSON mode to fall back to either: bind a schema that fits, or take the built-in one.
Passing submit is not the last check. When the run's result later misses a valid schema, the run fails with output_schema_unsatisfied instead; see Sume Format run failure codes.
Sources
Related posts
Written by Sume