{"record":{"id":"785e4af02fa947b7","repo":"colinhacks/zod","slug":"conditional-schemas-if-then-else-are-not-support","errorCode":null,"errorMessage":"Conditional schemas (if/then/else) are not supported","messagePattern":"Conditional schemas \\(if/then/else\\) are not supported","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/zod/src/v4/classic/from-json-schema.ts","lineNumber":163,"sourceCode":"}\n\nfunction convertBaseSchema(schema: JSONSchema.JSONSchema, ctx: ConversionContext): ZodType {\n  // Handle unsupported features\n  if (schema.not !== undefined) {\n    // Special case: { not: {} } represents never\n    if (typeof schema.not === \"object\" && Object.keys(schema.not).length === 0) {\n      return z.never();\n    }\n    throw new Error(\"not is not supported in Zod (except { not: {} } for never)\");\n  }\n  if (schema.unevaluatedItems !== undefined) {\n    throw new Error(\"unevaluatedItems is not supported\");\n  }\n  if (schema.unevaluatedProperties !== undefined) {\n    throw new Error(\"unevaluatedProperties is not supported\");\n  }\n  if (schema.if !== undefined || schema.then !== undefined || schema.else !== undefined) {\n    throw new Error(\"Conditional schemas (if/then/else) are not supported\");\n  }\n  if (schema.dependentSchemas !== undefined || schema.dependentRequired !== undefined) {\n    throw new Error(\"dependentSchemas and dependentRequired are not supported\");\n  }\n\n  // Handle $ref\n  if (schema.$ref) {\n    const refPath = schema.$ref;\n    if (ctx.refs.has(refPath)) {\n      return ctx.refs.get(refPath)!;\n    }\n\n    if (ctx.processing.has(refPath)) {\n      // Circular reference - use lazy\n      return z.lazy(() => {\n        if (!ctx.refs.has(refPath)) {\n          throw new Error(`Circular reference not resolved: ${refPath}`);\n        }","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/colinhacks/zod/blob/2d90846af918af9602e088812d63a035d47cdbe4/packages/zod/src/v4/classic/from-json-schema.ts#L145-L181","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst schema = {\n  type: 'object',\n  properties: { kind: { type: 'string' } },\n  if: { properties: { kind: { const: 'a' } } },\n  then: { required: ['aField'] },\n  else: { required: ['bField'] },\n};\nfromJSONSchema(schema); // throws\n\n// after — hand-write a discriminated union\nconst schema = z.discriminatedUnion('kind', [\n  z.object({ kind: z.literal('a'), aField: z.string() }),\n  z.object({ kind: z.literal('b'), bField: z.string() }),\n]);","handlingStrategy":"validation","validationCode":"function assertNoConditionals(root: unknown) {\n  const visit = (node: unknown): void => {\n    if (Array.isArray(node)) return node.forEach(visit);\n    if (!node || typeof node !== 'object') return;\n    const o = node as Record<string, unknown>;\n    if ('if' in o || 'then' in o || 'else' in o) {\n      throw new Error('Schema uses if/then/else conditionals, which Zod cannot express directly');\n    }\n    for (const v of Object.values(o)) visit(v);\n  };\n  visit(root);\n}","typeGuard":"null","tryCatchPattern":"null","preventionTips":["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."],"tags":["json-schema","from-json-schema","conversion","unsupported","conditional"],"backgroundTag":null,"analyzedSha":"2d90846af918af9602e088812d63a035d47cdbe4","analyzedAt":"2026-08-11T01:21:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}