can1357/oh-my-pi · error · OmpTypeError

JSON Schema nodes must be booleans or objects

Error message

JSON Schema nodes must be booleans or objects

What it means

Per JSON Schema spec, every schema node must be a boolean (`true`/`false`, meaning accept-anything/accept-nothing) or an object of keywords. `fromJsonSchema.lower()` throws when it encounters any other value — a string, number, array, or null — where a schema node was expected.

Source

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

		// 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;
	}

	lower(schema: unknown): IR {
		if (schema === true) return { k: "unknown" };
		if (schema === false) return { k: "never" };
		if (typeof schema !== "object" || schema === null) {
			throw new OmpTypeError("JSON Schema nodes must be booleans or objects");
		}
		const node = schema as JsonSchema;
		const desc = typeof node.description === "string" ? node.description : undefined;
		const ir = this.#lowerNode(node);
		return desc === undefined ? ir : { ...ir, desc };
	}

	#lowerNode(node: JsonSchema): IR {
		if (typeof node.$ref === "string") return this.resolveRef(node.$ref);

		if (Array.isArray(node.enum)) {
			const members = node.enum.map((v): IR => ({ k: "lit", v }));
			return members.length === 1 ? members[0] : { k: "union", members };
		}
		if ("const" in node) return { k: "lit", v: node.const };

		const branches = node.anyOf ?? node.oneOf;
		if (Array.isArray(branches)) {

View on GitHub (pinned to 9690622007)

Solutions

  1. Replace the invalid node with a real schema object, e.g. `{ "type": "string" }` or `true`.
  2. Use `true`/`false` instead of null when you mean 'any' / 'never'.
  3. For nullable values, use `{ "type": ["string", "null"] }` rather than a null node.

Example fix

// before
{ "properties": { "name": null } }
// after
{ "properties": { "name": { "type": ["string", "null"] } } }
Defensive patterns

Strategy: validation

Validate before calling

function isSchemaNode(v: unknown): boolean {
  return v === true || v === false || (typeof v === "object" && v !== null && !Array.isArray(v));
}
// apply to root, each properties value, items, etc.

Type guard

function isSchemaNode(v: unknown): v is boolean | Record<string, unknown> {
  return v === true || v === false || (typeof v === "object" && v !== null && !Array.isArray(v));
}

Prevention

When it happens

Trigger: Passing a schema where `properties` values, `items`, or the root are `null`, strings, or numbers; calling `lower(x)` directly with a non-schema value.

Common situations: JSON-parsed configs where `"schema": null`; OpenAPI-style schemas with `nullable: true` confused with a `null` node; hand-built schemas in JS that put non-schema values in keyword positions.

Related errors


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