colinhacks/zod · error · Error

unevaluatedItems is not supported

Error message

unevaluatedItems is not supported

What it means

Thrown by convertBaseSchema when the input contains `unevaluatedItems`. This draft-2019+/2020-12 keyword dynamically constrains items not validated by adjacent applicators, which has no static counterpart in Zod's tuple/array model.

Source

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

      throw new Error(`Reference not found: ${ref}`);
    }
    return ctx.defs[key]!;
  }

  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)!;
    }

View on GitHub (pinned to 912f0f51b0)

Solutions

  1. Remove the `unevaluatedItems` keyword; the converter will then treat items/tuple constraints normally.
  2. Re-express the intent with `items: false` or an explicit `prefixItems` + `maxItems` pair where possible.
  3. Pre-process the schema to delete unsupported keywords before passing it in.

Example fix

// before
{ "prefixItems": [{ "type": "string" }], "unevaluatedItems": false }

// after
{ "prefixItems": [{ "type": "string" }], "maxItems": 1 }
Defensive patterns

Strategy: validation

Validate before calling

function stripUnsupported(schema: any) {
  if (schema.unevaluatedItems !== undefined) {
    delete schema.unevaluatedItems;
  }
}

Type guard

function hasUnevaluatedItems(s: any): boolean { return s?.unevaluatedItems !== undefined; }

Prevention

When it happens

Trigger: A JSON Schema (draft 2019-09 or 2020-12) containing `unevaluatedItems: false` or `unevaluatedItems: { ... }`, often alongside `prefixItems` or `allOf`.

Common situations: Schemas authored for strict additional-item control; LLM/IDE-generated schemas using newer keywords; importing schemas from tools that emit full draft-2020-12.

Related errors


AI-assisted analysis of colinhacks/zod@912f0f51b0 (2026-08-03). Data as JSON: /data/errors/892885ff562bf460.json. Report an issue: GitHub.