colinhacks/zod · error · Error

dependentSchemas and dependentRequired are not supported

Error message

dependentSchemas and dependentRequired are not supported

What it means

Thrown by convertBaseSchema (packages/zod/src/v4/classic/from-json-schema.ts:166) when the source JSON Schema uses `dependentSchemas` or `dependentRequired` (draft-2019+ keywords that make property requirements conditional on the presence of other properties). Zod has no native combinator for 'if this key is present then require those keys', so the converter rejects the document.

Solutions

  1. Express the dependency as a post-conversion .superRefine() that checks the conditional and pushes an issue on the dependent path.
  2. Rewrite as a z.discriminatedUnion or z.union where each branch is a self-contained object schema representing one valid combination.
  3. Remove the dependent* keys if they encode optional business rules you can enforce outside the schema.
  4. Pre-process to translate dependentRequired into explicit union branches before conversion.

Example fix

// before
const schema = {
  type: 'object',
  properties: { creditCard: { type: 'string' }, billingAddress: { type: 'string' } },
  dependentRequired: { creditCard: ['billingAddress'] },
};
fromJSONSchema(schema); // throws

// after — enforce the dependency with a refinement
const schema = z
  .object({
    creditCard: z.string().optional(),
    billingAddress: z.string().optional(),
  })
  .superRefine((v, ctx) => {
    if (v.creditCard && !v.billingAddress) {
      ctx.addIssue({
        code: 'custom',
        path: ['billingAddress'],
        message: 'billingAddress is required when creditCard is set',
      });
    }
  });
Defensive patterns

Strategy: validation

Validate before calling

function assertNoDependent(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 ('dependentSchemas' in o || 'dependentRequired' in o) {
      throw new Error('Schema uses dependentSchemas/dependentRequired, which Zod cannot express directly');
    }
    for (const v of Object.values(o)) visit(v);
  };
  visit(root);
}

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: Calling fromJSONSchema on a schema containing `dependentRequired: { creditCard: ['billingAddress'] }` or `dependentSchemas: { foo: { required: ['bar'] } }`. The presence of either key triggers the throw.

Common situations: Real-world form schemas (e.g. require billingAddress when creditCard is set); draft-2019+ documents that formalised the older draft-7 'dependencies' keyword into these two; OpenAPI 3.1 schemas that adopt the 2019-09 vocabulary; strict enterprise schemas.

Related errors


AI-assisted analysis of colinhacks/zod@2d90846af9 (2026-08-11). Data as JSON: /api/errors/b3e2b6de5d31a7cc. Report an issue: GitHub.

Appendix: source

Thrown at packages/zod/src/v4/classic/from-json-schema.ts:166

  // 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}`);
        }
        return ctx.refs.get(refPath)!;
      });
    }

View on GitHub (pinned to 2d90846af9)