can1357/oh-my-pi · error · OmpTypeError

onUndeclaredKey requires an object schema

Error message

onUndeclaredKey requires an object schema

What it means

withShallowExtras() can only attach onUndeclaredKey behavior to object-shaped IR (spreading shallowly through unions/aliases). If after resolution the schema is not an object (or a union/alias of objects), there is nowhere to attach key handling, so omptype throws.

Source

Thrown at packages/omptype/src/type.ts:1877

	}
	return {
		k: "object",
		props,
		index: right.index ?? left.index,
		symbolIndex: right.symbolIndex ?? left.symbolIndex,
		patternIndexes:
			left.patternIndexes === undefined && right.patternIndexes === undefined
				? undefined
				: [...(left.patternIndexes ?? []), ...(right.patternIndexes ?? [])],
		extras: right.extras === "keep" ? left.extras : right.extras,
	};
}

function withShallowExtras(ir: IR, extras: ObjectIR["extras"]): IR {
	if (ir.k === "object") return { ...ir, extras };
	if (ir.k === "union") return { ...ir, members: ir.members.map(member => withShallowExtras(member, extras)) };
	if (ir.k === "alias") return withShallowExtras(ir.resolve(), extras);
	throw new OmpTypeError("onUndeclaredKey requires an object schema");
}

function withDeepExtras(ir: IR, extras: ObjectIR["extras"]): IR {
	switch (ir.k) {
		case "object":
			return {
				...ir,
				extras,
				props: ir.props.map(prop => ({ ...prop, val: withDeepExtras(prop.val, extras) })),
				index: ir.index === undefined ? undefined : withDeepExtras(ir.index, extras),
				symbolIndex: ir.symbolIndex === undefined ? undefined : withDeepExtras(ir.symbolIndex, extras),
				patternIndexes: ir.patternIndexes?.map(index => ({
					key: withDeepExtras(index.key, extras),
					val: withDeepExtras(index.val, extras),
				})),
			};
		case "array":
			return { ...ir, el: withDeepExtras(ir.el, extras) };

View on GitHub (pinned to 9690622007)

Solutions

  1. Call onUndeclaredKey on the object schema itself: type({...}).onUndeclaredKey('delete')
  2. If you need it inside a collection, apply it to the element schema: array(type({...}).onUndeclaredKey('strip'))
  3. For unions, ensure every member is an object; extract the object member you meant
  4. Verify the schema variable holds an object type, not a transformed/morph result

Example fix

// before
array(itemSchema).onUndeclaredKey('strip')
// after
array(itemSchema.onUndeclaredKey('strip'))
Defensive patterns

Strategy: type-guard

Validate before calling

function assertObjectSchema(schema) {
  if (typeof schema?.assert !== 'function') throw new Error('not an omptype schema');
  // try a round-trip to confirm object-shaped:
  try { schema.assert({}); } catch { /* object types may reject {} — acceptable */ }
}

Type guard

function isObjectSchema(t): t is InternalType {
  return typeof t === 'object' && t !== null && (t.ir?.k === 'object' || t.ir?.k === 'union' || t.ir?.k === 'alias');
}

Try / catch

try {
  return schema.onUndeclaredKey('strip');
} catch (err) {
  if (err instanceof OmpTypeError && err.message.includes('onUndeclaredKey requires an object schema')) {
    throw new Error('apply onUndeclaredKey to the inner object schema, not the wrapper');
  }
  throw err;
}

Prevention

When it happens

Trigger: string().onUndeclaredKey('delete'), array(...).onUndeclaredKey(...), or a morph/intersection schema passed to onUndeclaredKey.

Common situations: Chaining onUndeclaredKey on the wrong schema in a fluent chain; applying it to a union that contains a non-object branch after refactoring; forgetting the outer type is wrapped (e.g. array of objects).

Related errors


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