colinhacks/zod · error · Error
External $ref is not supported, only local refs (#/...) are
Error message
External $ref is not supported, only local refs (#/...) are allowed
What it means
Thrown by resolveRef in the v4 JSON-Schema-to-Zod converter when a `$ref` does not start with `#`. Only local (same-document) refs are supported; the converter has no mechanism to fetch or embed external schema documents.
Source
Thrown at packages/zod/src/v4/classic/from-json-schema.ts:123
const $schema = schema.$schema;
if ($schema === "https://json-schema.org/draft/2020-12/schema") {
return "draft-2020-12";
}
if ($schema === "http://json-schema.org/draft-07/schema#") {
return "draft-7";
}
if ($schema === "http://json-schema.org/draft-04/schema#") {
return "draft-4";
}
// Use defaultTarget if provided, otherwise default to draft-2020-12
return defaultTarget ?? "draft-2020-12";
}
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]!;
}View on GitHub (pinned to 912f0f51b0)
Solutions
- Inline external definitions into a single `$defs` (draft 2020-12) or `definitions` (draft-07) block and rewrite refs to `#/$defs/Name`.
- Use a JSON Schema bundler (e.g. @apidevtools/json-schema-ref-parser) to resolve external refs before passing to fromJSONSchema.
- Drop or replace external refs with locally-defined equivalents if the external schema is small.
Example fix
// before
{ "$ref": "https://example.com/user.json" }
// after
{
"$defs": { "user": { "type": "object", ... } },
"$ref": "#/$defs/user"
} Defensive patterns
Strategy: validation
Validate before calling
function assertLocalRefs(root: any, path = "") {
const visit = (node: any) => {
if (!node || typeof node !== "object") return;
if (typeof node.$ref === "string" && !node.$ref.startsWith("#")) {
throw new Error(`External ref at ${path}: ${node.$ref}`);
}
for (const k of Object.keys(node)) visit(node[k]);
};
visit(root);
} Type guard
function isLocalRef(ref: string): boolean {
return typeof ref === "string" && ref.startsWith("#");
} Prevention
- Run a JSON Schema bundler before conversion to inline external refs.
- Keep schemas self-contained in a single document with `$defs`.
- Add a CI check that rejects schemas containing external `$ref` values.
When it happens
Trigger: Passing a JSON Schema whose `$ref` points at another file or URL, e.g. `{ "$ref": "./user.json" }`, `{ "$ref": "https://example.com/schemas/user" }`, or `{ "$ref": "defs.json#/User" }`.
Common situations: Loading OpenAPI/JSON Schema bundles that split definitions across files; consuming third-party schemas that reference a shared registry by URL; bundlers that do not inline external refs.
Related errors
- Reference not found: ${ref}
- not is not supported in Zod (except { not: {} } for never)
- unevaluatedItems is not supported
- unevaluatedProperties is not supported
- Conditional schemas (if/then/else) are not supported
AI-assisted analysis of colinhacks/zod@912f0f51b0 (2026-08-03).
Data as JSON: /data/errors/fa5bef923e27c0c9.json.
Report an issue: GitHub.