can1357/oh-my-pi · error · OmpTypeError

A default may only be specified for an object property or tu

Error message

A default may only be specified for an object property or tuple element

What it means

When parseDef parses a string definition (or array expression) it rejects any result that carries a default: defaults are only meaningful in positions that map to a storage slot — an object property or a tuple element. A bare top-level definition like "string=foo" has nothing to attach the default to, so it throws.

Source

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

	const object: IR = {
		k: "object",
		props,
		index: indexes?.string,
		symbolIndex: indexes?.symbol,
		patternIndexes: indexes === undefined || indexes.patterns.length === 0 ? undefined : indexes.patterns,
		extras,
	};
	object[kSimple] = simple;
	object[kSimpleOwner] = object;
	return object;
}

/** Parse a definition, optionally resolving names from an enclosing scope. */
export function parseDef(def: unknown, resolve?: AliasResolver): IR {
	if (typeof def === "string") {
		const parsed = parseStringDef(def, resolve);
		if (parsed.hasDefault) {
			throw new OmpTypeError("A default may only be specified for an object property or tuple element");
		}
		if (parsed.optional) {
			throw new OmpTypeError(`optional "?" marker is only valid on object property values`);
		}
		return parsed.ir;
	}
	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)) {

View on GitHub (pinned to 9690622007)

Solutions

  1. Remove the "=default" suffix from the standalone definition
  2. Wrap it as an object property or tuple element where defaults are allowed
  3. Split into the plain type plus a separate default value handled by your own code

Example fix

// before
const T = type("string='hello'")
// after
const T = type({ key: "string='hello'" })
Defensive patterns

Strategy: type-guard

Validate before calling

function assertNoTopLevelDefault(def) {
  if (typeof def === "string" && /=/.test(def.split("|")[0])) {
    // conservative check for "=default" suffix outside property position
    throw new Error("remove the =default from the standalone definition");
  }
  if (Array.isArray(def) && def.length === 3 && def[1] === "=") {
    throw new Error("defaulted array form only valid as property/tuple value");
  }
}

Type guard

const isDefaultedForm = (d) => (Array.isArray(d) && d.length === 3 && d[1] === "=");

Try / catch

try { const T = type(def); } catch (e) {
  if (e.message.includes("A default may only be specified")) {
    // move def into an object property or tuple element, or strip the default
  } else throw e;
}

Prevention

When it happens

Trigger: Calling parseDef (directly or via type()) with a string def that parseStringDef parses with hasDefault set, or an array def of length 3 with "=" at index 1 — i.e. a default written outside an object property or tuple element position.

Common situations: Copying a property's string including its "=value" suffix into a standalone type; passing a defaulted expression where a plain type is expected (function parameter, union member, alias body).

Related errors


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