can1357/oh-my-pi · error · OmpTypeError

unsupported $ref: ${ref}

Error message

unsupported $ref: ${ref}

What it means

`fromJsonSchema` only supports root refs (`#`) and local definition refs of the form `#/$defs/Name` or `#/definitions/Name`. Any other `$ref` syntax (external URLs, escaped pointers, nested pointer paths) throws this `OmpTypeError`. The library deliberately does not resolve remote or arbitrary JSON-pointer refs.

Source

Thrown at packages/omptype/src/from-json-schema.ts:49

class Importer {
	readonly #root: JsonSchema;
	readonly #aliases = new Map<string, IR>();

	constructor(root: JsonSchema) {
		this.#root = root;
	}

	resolveRef(ref: string): IR {
		const cached = this.#aliases.get(ref);
		if (cached !== undefined) return cached;

		let target: unknown;
		if (ref === "#") {
			target = this.#root;
		} else {
			const defsMatch = /^#\/(\$defs|definitions)\/(.+)$/.exec(ref);
			if (defsMatch === null) throw new OmpTypeError(`unsupported $ref: ${ref}`);
			const defs = this.#root[defsMatch[1]];
			target = typeof defs === "object" && defs !== null ? (defs as JsonSchema)[defsMatch[2]] : undefined;
			if (target === undefined) throw new OmpTypeError(`unresolved $ref: ${ref}`);
		}

		// Register the alias before lowering so recursive references resolve
		// to the same node instead of recursing forever.
		let lowered: IR | undefined;
		const alias: IR = {
			k: "alias",
			name: ref,
			resolve: () => {
				lowered ??= this.lower(target);
				return lowered;
			},
		};
		this.#aliases.set(ref, alias);
		return alias;

View on GitHub (pinned to 9690622007)

Solutions

  1. Rewrite the schema so all `$ref`s point to `#/$defs/Name` or `#/definitions/Name` in the same document.
  2. Pre-resolve external/nested refs yourself (bundle the schema with a tool like `@apidevtools/json-schema-ref-parser`) before conversion.
  3. Inline the referenced subschema at the ref site if bundling isn't possible.

Example fix

// before
{ "$ref": "http://example.com/common.json#/definitions/Id" }
// after
{ "$ref": "#/$defs/Id" } // with "Id" defined in $defs of the same schema
Defensive patterns

Strategy: validation

Validate before calling

function hasOnlySupportedRefs(schema: { $ref?: string } & Record<string, unknown>): boolean {
  if (typeof schema.$ref === "string" && !/^#\/(\$defs|definitions)\/[^/]+$/.test(schema.$ref)) return false;
  return Object.values(schema).every(v => typeof v !== "object" || v === null || hasOnlySupportedRefs(v as never));
}

Try / catch

try {
  const t = fromJsonSchema(schema);
} catch (err) {
  if (err instanceof Error && err.message.startsWith("unsupported $ref")) {
    throw new Error(`Bundle schema first: ${err.message}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Passing a JSON Schema whose `$ref` is e.g. `"http://example.com/schema"`, `"#/definitions/a/b"`, `"#/definitions/A/properties/x"`, or `"other.json#/definitions/A"` to `fromJsonSchema`.

Common situations: Schemas generated by tools that emit external refs (`$id`-based references); OpenAPI documents with `components` refs; schemas with escaped-pointer keys (`~0`, `~1`).

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/03d7c495bbf255df. Report an issue: GitHub.