colinhacks/zod · error · Error
Conditional schemas (if/then/else) are not supported
Error message
Conditional schemas (if/then/else) are not supported
What it means
Thrown by convertBaseSchema (packages/zod/src/v4/classic/from-json-schema.ts:163) when the source JSON Schema uses conditional composition (`if`, `then`, or `else`). JSON Schema's conditional construct has no direct Zod combinator — Zod's unions are structural, not predicate-driven — so the converter rejects the document rather than silently producing a wrong schema.
Solutions
- Rewrite the conditional as a discriminated union or z.union of explicit branches before conversion, then convert each branch.
- Hand-write the equivalent Zod schema using z.discriminatedUnion (if there is a clear discriminator) or z.union with per-branch refinements.
- Strip the if/then/else keys if they encode business logic you can move into a post-conversion .superRefine().
- Identify the branching field and express each option as a self-contained object schema.
Example fix
// before
const schema = {
type: 'object',
properties: { kind: { type: 'string' } },
if: { properties: { kind: { const: 'a' } } },
then: { required: ['aField'] },
else: { required: ['bField'] },
};
fromJSONSchema(schema); // throws
// after — hand-write a discriminated union
const schema = z.discriminatedUnion('kind', [
z.object({ kind: z.literal('a'), aField: z.string() }),
z.object({ kind: z.literal('b'), bField: z.string() }),
]); Defensive patterns
Strategy: validation
Validate before calling
function assertNoConditionals(root: unknown) {
const visit = (node: unknown): void => {
if (Array.isArray(node)) return node.forEach(visit);
if (!node || typeof node !== 'object') return;
const o = node as Record<string, unknown>;
if ('if' in o || 'then' in o || 'else' in o) {
throw new Error('Schema uses if/then/else conditionals, which Zod cannot express directly');
}
for (const v of Object.values(o)) visit(v);
};
visit(root);
} Type guard
null
Try / catch
null
Prevention
- Rewrite if/then/else as a discriminated union or z.union of explicit branches before conversion.
- Move conditional logic into a post-conversion .superRefine() when a union is impractical.
- Scan incoming OpenAPI 3.1 / JSON Schema documents for conditional keywords before conversion.
- Hand-author complex conditional schemas in Zod instead of converting.
When it happens
Trigger: Calling fromJSONSchema on a schema that contains any of `if`, `then`, or `else` keys, e.g. `{ if: { properties: { kind: { const: 'a' } } }, then: {...}, else: {...} }`. The presence of any one of the three triggers the throw.
Common situations: Schemas that branch validation based on a discriminator-like field; OpenAPI 3.1 documents using JSON Schema conditionals; schemas expressing 'if property X then require Y' rules; auto-generated schemas from discriminated TypeScript unions.
Related errors
- dependentSchemas and dependentRequired are not supported
- not is not supported in Zod
- unevaluatedItems is not supported
- unevaluatedProperties is not supported
- Unsupported type
AI-assisted analysis of colinhacks/zod@2d90846af9 (2026-08-11).
Data as JSON: /api/errors/785e4af02fa947b7.
Report an issue: GitHub.
Appendix: source
Thrown at packages/zod/src/v4/classic/from-json-schema.ts:163
}
function convertBaseSchema(schema: JSONSchema.JSONSchema, ctx: ConversionContext): ZodType {
// Handle unsupported features
if (schema.not !== undefined) {
// Special case: { not: {} } represents never
if (typeof schema.not === "object" && Object.keys(schema.not).length === 0) {
return z.never();
}
throw new Error("not is not supported in Zod (except { not: {} } for never)");
}
if (schema.unevaluatedItems !== undefined) {
throw new Error("unevaluatedItems is not supported");
}
if (schema.unevaluatedProperties !== undefined) {
throw new Error("unevaluatedProperties is not supported");
}
if (schema.if !== undefined || schema.then !== undefined || schema.else !== undefined) {
throw new Error("Conditional schemas (if/then/else) are not supported");
}
if (schema.dependentSchemas !== undefined || schema.dependentRequired !== undefined) {
throw new Error("dependentSchemas and dependentRequired are not supported");
}
// Handle $ref
if (schema.$ref) {
const refPath = schema.$ref;
if (ctx.refs.has(refPath)) {
return ctx.refs.get(refPath)!;
}
if (ctx.processing.has(refPath)) {
// Circular reference - use lazy
return z.lazy(() => {
if (!ctx.refs.has(refPath)) {
throw new Error(`Circular reference not resolved: ${refPath}`);
}View on GitHub (pinned to 2d90846af9)