colinhacks/zod · error · Error

Reference not found: ${ref}

Error message

Reference not found: ${ref}

What it means

Thrown by resolveRef when a `#/...` ref correctly points into `$defs`/`definitions` but the named key is missing (or empty). The converter looked up `ctx.defs[key]` and it was undefined.

Source

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

function resolveRef(ref: string, ctx: ConversionContext): JSONSchema.JSONSchema {
  if (!ref.startsWith("#")) {
    throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
  }

  const path = ref.slice(1).split("/").filter(Boolean);

  // Handle root reference "#"
  if (path.length === 0) {
    return ctx.rootSchema;
  }

  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";

  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");

View on GitHub (pinned to 912f0f51b0)

Solutions

  1. Add the missing definition under `$defs` (or `definitions` for draft-7) with the exact key from the ref.
  2. Verify the defs container name matches the detected draft (`$schema` header); convert to the matching key.
  3. Search the schema for every `$ref` and confirm each target exists in `$defs`/`definitions`.

Example fix

// before
{ "$ref": "#/$defs/User" } // no $defs.User present

// after
{
  "$defs": {
    "User": { "type": "object", "properties": { "id": { "type": "string" } } }
  },
  "$ref": "#/$defs/User"
}
Defensive patterns

Strategy: validation

Validate before calling

function assertRefsResolve(schema: any) {
  const defs = schema.$defs ?? schema.definitions ?? {};
  const visit = (n: any) => {
    if (n && typeof n === "object") {
      if (typeof n.$ref === "string") {
        const key = n.$ref.split("/").pop();
        if (!defs[key]) throw new Error(`Unresolved $ref: ${n.$ref}`);
      }
      Object.values(n).forEach(visit);
    }
  };
  visit(schema);
}

Type guard

function defsHasKey(schema: any, ref: string): boolean {
  const defs = schema.$defs ?? schema.definitions ?? {};
  const key = ref.split("/").pop();
  return key != null && key in defs;
}

Prevention

When it happens

Trigger: A schema with `{ "$ref": "#/$defs/User" }` but no `$defs.User` entry; renaming a definition without updating its ref; using the wrong defs key for the detected draft version.

Common situations: Hand-editing schemas and dropping a definition; copy-paste that changes the path but not the key; mixing draft-7 `definitions` with 2020-12 `$defs` while the converter resolves under one key only.

Related errors


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