colinhacks/zod · error · Error

not is not supported in Zod (except { not: {} } for never)

Error message

not is not supported in Zod (except { not: {} } for never)

What it means

Thrown by convertBaseSchema when a JSON Schema uses the `not` keyword in any form other than `{ not: {} }`, which the converter maps to z.never(). General negation constraints are not representable in Zod's additive model.

Source

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

  if (path[0] === defsKey) {
    const key = path[1];
    if (!key || !ctx.defs[key]) {
      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)) {

View on GitHub (pinned to 912f0f51b0)

Solutions

  1. If you intend 'reject everything' use `{ not: {} }`, which converts to z.never().
  2. Replace `not` with an affirmative constraint expressible in Zod: e.g. use `anyOf`/`oneOf` to enumerate allowed shapes, or move the negation into a `.refine()` after conversion.
  3. Strip `not` from the source schema and apply the equivalent check downstream in code.

Example fix

// before
{ "not": { "type": "string" } } // 'not a string'

// after
// enumerate allowed types instead, then refine
const s = z.any().refine((v) => typeof v !== "string", "must not be a string");
Defensive patterns

Strategy: validation

Validate before calling

function assertNoNot(schema: any) {
  if (schema.not !== undefined && !(typeof schema.not === "object" && Object.keys(schema.not).length === 0)) {
    throw new Error("`not` is unsupported; only { not: {} } is allowed");
  }
}

Type guard

function isSupportedNot(schema: any): boolean {
  return schema.not === undefined || (typeof schema.not === "object" && Object.keys(schema.not).length === 0);
}

Prevention

When it happens

Trigger: A schema like `{ not: { type: "string" } }` (anything except a string), `{ not: { enum: [...] } }`, or `{ not: { const: 0 } }`. Even `{ not: { type: "object" } }` is rejected.

Common situations: Inheriting schemas authored for Ajv or other validators that fully support `not`; OpenAPI extensions that use `not` to forbid shapes; trying to express 'not one of' constraints.

Related errors


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