colinhacks/zod · error · Error
unevaluatedProperties is not supported
Error message
unevaluatedProperties is not supported
What it means
Thrown by convertBaseSchema (packages/zod/src/v4/classic/from-json-schema.ts:160) when the source JSON Schema contains the `unevaluatedProperties` keyword (a draft-2019+ feature constraining object properties not matched by properties/patternProperties/additionalProperties). Because Zod objects resolve extra-key handling statically (strip/passthrough/strict/catchall), there is no way to express the dynamic 'unevaluated' behaviour, so the converter rejects the document.
Solutions
- Remove the `unevaluatedProperties` key before conversion.
- If the intent was strict no-extras, use additionalProperties: false in the source — the converter maps that to z.object().strict().
- If extras should match a schema, use additionalProperties as a schema object — the converter maps that to .catchall().
- Pre-process to strip draft-2019+ keys the converter does not support.
Example fix
// before
const schema = {
type: 'object',
properties: { id: { type: 'string' } },
unevaluatedProperties: false,
};
fromJSONSchema(schema); // throws
// after — use additionalProperties: false (maps to .strict())
const schema = {
type: 'object',
properties: { id: { type: 'string' } },
additionalProperties: false,
};
fromJSONSchema(schema); Defensive patterns
Strategy: validation
Validate before calling
function assertNoUnevaluatedProperties(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 ('unevaluatedProperties' in o) throw new Error('Schema uses unevaluatedProperties, which Zod cannot express');
for (const v of Object.values(o)) visit(v);
};
visit(root);
} Type guard
null
Try / catch
null
Prevention
- Use additionalProperties: false (maps to .strict()) or additionalProperties as a schema (maps to .catchall()) instead of unevaluatedProperties.
- Strip unevaluatedProperties from draft-2019+ documents before conversion.
- Audit strict enterprise schemas for unevaluated* usage before importing.
- Document the mapping (additionalProperties -> Zod) for schema authors.
When it happens
Trigger: Calling fromJSONSchema on a schema like `{ type: 'object', properties: {...}, unevaluatedProperties: false }` or `unevaluatedProperties: { type: 'string' }`. The presence of the key alone — value irrelevant — triggers the throw.
Common situations: Strict draft-2019/2020-12 schemas that forbid unknown properties via unevaluatedProperties; OpenAPI 3.1 documents using the newer vocabulary; schemas exported from strict validation tooling.
Related errors
- Conditional schemas (if/then/else) are not supported
- dependentSchemas and dependentRequired are not supported
- not is not supported in Zod
- unevaluatedItems is not supported
- Unsupported type
AI-assisted analysis of colinhacks/zod@2d90846af9 (2026-08-11).
Data as JSON: /api/errors/feda1447c554dd47.
Report an issue: GitHub.
Appendix: source
Thrown at packages/zod/src/v4/classic/from-json-schema.ts:160
}
throw new Error(`Reference not found: ${ref}`);
}
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(() => {View on GitHub (pinned to 2d90846af9)