colinhacks/zod · error · Error
Reference not found
Error message
Reference not found: ${ref} What it means
Thrown by resolveRef (packages/zod/src/v4/classic/from-json-schema.ts:139) when a local $ref correctly points into $defs/definitions (path[0] === defsKey) but the named key does not exist or is empty. The converter walks the path, finds the defs bucket for the detected draft, looks up the key in ctx.defs, and rejects when the lookup misses — meaning the document references a definition it never declared.
Solutions
- Check that every name referenced by #/$defs/Name (or #/definitions/Name) exists in the document's $defs/definitions object.
- Confirm the document's $schema matches the bucket name used by refs: draft-2020-12 uses $defs, draft-7 uses definitions — the converter picks the bucket based on $schema.
- Run the document through a JSON Schema validator/IDE to flag dangling references before conversion.
- Add the missing definition or rewrite the ref to point at an existing one.
Example fix
// before
const schema = {
$schema: 'https://json-schema.org/draft/2020-12/schema',
$ref: '#/$defs/User',
$defs: { Account: { type: 'object' } }, // 'User' missing
};
// after
const schema = {
$schema: 'https://json-schema.org/draft/2020-12/schema',
$ref: '#/$defs/User',
$defs: { User: { type: 'object', properties: { id: { type: 'string' } } } },
}; Defensive patterns
Strategy: validation
Validate before calling
function collectDefinedNames(root: any, version: 'draft-2020-12' | 'draft-7'): Set<string> {
const defsKey = version === 'draft-2020-12' ? '$defs' : 'definitions';
return new Set(Object.keys(root?.[defsKey] ?? {}));
}
function assertRefsResolve(root: any, version: 'draft-2020-12' | 'draft-7') {
const names = collectDefinedNames(root, version);
const defsKey = version === 'draft-2020-12' ? '$defs' : 'definitions';
const dangling: string[] = [];
const visit = (node: unknown) => {
if (Array.isArray(node)) return node.forEach(visit);
if (!node || typeof node !== 'object') return;
const o = node as Record<string, unknown>;
if (typeof o.$ref === 'string' && o.$ref.startsWith(`#/${defsKey}/`)) {
const name = o.$ref.split('/')[2];
if (!names.has(name!)) dangling.push(o.$ref);
}
for (const v of Object.values(o)) visit(v);
};
visit(root);
if (dangling.length) throw new Error(`Dangling refs: ${dangling.join(', ')}`);
} Type guard
null
Try / catch
null
Prevention
- Confirm every #/$defs/Name (or #/definitions/Name) reference has a matching entry in the document's definitions bucket.
- Match the refs' bucket name to the document's declared $schema ($defs for 2020-12, definitions for draft-7).
- Validate the source document with a JSON Schema linter before conversion.
- When renaming a definition, update all references to it in the same change.
When it happens
Trigger: Calling fromJSONSchema with a schema like `{ "$ref": "#/$defs/Missing" }` or `{ "$ref": "#/definitions/Missing" }` where 'Missing' is not present in the corresponding $defs/definitions object. Also triggered when the $defs key is misspelled or uses the wrong draft's bucket name for the detected version.
Common situations: Renaming a definition without updating its references; truncating a schema document so $defs is dropped; mixing draft-7 'definitions' refs into a draft-2020-12 document (or vice-versa) so the defsKey lookup fails; typos in the definition name; copy-paste of refs from another schema.
Related errors
- External $ref is not supported, only local refs (#/...) are…
- Circular reference not resolved
- Conditional schemas (if/then/else) are not supported
- Cycle detected: #/ / Set the `cycles` parameter to `"ref"`…
- dependentSchemas and dependentRequired are not supported
AI-assisted analysis of colinhacks/zod@2d90846af9 (2026-08-11).
Data as JSON: /api/errors/436328b19188ff6f.
Report an issue: GitHub.
Appendix: source
Thrown at packages/zod/src/v4/classic/from-json-schema.ts:139
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 2d90846af9)