can1357/oh-my-pi · error · OmpTypeError

unsupported definition ${String(def)} (was ${typeof def})

Error message

unsupported definition ${String(def)} (was ${typeof def})

What it means

parseDef is the universal definition entrypoint: strings, arrays, RegExp, Date, embeddable types, thunks, and object definitions are all accepted. Anything falling through all branches — undefined, null, a number, a boolean, an arbitrary class instance — reaches the final throw, which echoes the value and its typeof so you can see what was passed.

Source

Thrown at packages/omptype/src/ir.ts:1521

	}
	if (Array.isArray(def)) {
		if (def.length === 3 && def[1] === "=") {
			throw new OmpTypeError("A default may only be specified for an object property or tuple element");
		}
		return parseArrayExpression(def, resolve);
	}
	if (def instanceof RegExp) return patternIR(def);
	if (def instanceof Date) return { k: "lit", v: def };
	if (isEmbedded(def)) return embed(def);
	if (typeof def === "function") {
		const resolved = Reflect.apply(def, undefined, []);
		if (!isEmbedded(resolved)) {
			throw new OmpTypeError(`thunk must return a Type (was ${typeof resolved})`);
		}
		return embed(resolved);
	}
	if (isObjectDefinition(def)) return parseObjectDefinition(def, resolve);
	throw new OmpTypeError(`unsupported definition ${String(def)} (was ${typeof def})`);
}

/** Whether `ir` needs no construction-time normalization or morph analysis. */
export function isSimpleIR(ir: IR): boolean {
	const cached = ir[kSimpleOwner] === ir ? ir[kSimple] : undefined;
	if (cached !== undefined) return cached;
	const simple = scanSimpleIR(ir);
	ir[kSimple] = simple;
	ir[kSimpleOwner] = ir;
	return simple;
}

function scanSimpleIR(ir: IR): boolean {
	switch (ir.k) {
		case "intersection":
		case "morph":
		case "sub":
		case "alias":

View on GitHub (pinned to 9690622007)

Solutions

  1. Log the definition value (the message echoes it) to find where undefined/garbage originates
  2. Convert primitives into valid defs, e.g. type("'42'") for a literal or type(String(x)) for a def string
  3. Validate inputs before passing them to type()
  4. If integrating another schema library, convert it to an omptype definition first

Example fix

// before
const T = type(config.fieldType) // config.fieldType is undefined
// after
const def = config.fieldType ?? "string"
const T = type(def)
Defensive patterns

Strategy: try-catch

Validate before calling

function isSupportedDef(def) {
  return typeof def === "string" || Array.isArray(def) || def instanceof RegExp
    || def instanceof Date || typeof def === "function"
    || (def !== null && typeof def === "object");
}
if (def === undefined || def === null || typeof def === "number" || typeof def === "boolean")
  throw new Error("unsupported definition before calling type()");

Type guard

const isSupportedDef = (d) => d != null && (typeof d === "string" || typeof d === "object" || typeof d === "function");

Try / catch

try { const T = type(def); } catch (e) {
  if (String(e.message).startsWith("unsupported definition")) {
    // the message echoes the value and typeof — log it to find the bad input source
  } else throw e;
}

Prevention

When it happens

Trigger: Calling type()/parseDef with a value outside the supported definition grammar: primitives like 42 or true, null/undefined (often from a failed lookup or optional chain), or a foreign schema object from another library.

Common situations: Config lookups returning undefined (missing env var, typo'd key) passed straight into type(); JSON-parsed schemas containing raw numbers; mixing another validator's (zod/yup) schema objects into omptype definitions; array holes or sparse defaults.

Related errors


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