can1357/oh-my-pi · error · OmpTypeError

"this" cannot be used as a root definition

Error message

"this" cannot be used as a root definition

What it means

Inside a definition, the self-reference 'this' resolves via an alias IR whose resolve() throws when the root definition is not yet available or when the alias resolves to itself. Using 'this' as the entire root definition means resolution is circular with no base case, so the library throws OmpTypeError.

Source

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

	resolve.hasGeneric = outer?.hasGeneric;
	resolve.generic = outer?.generic;
	return resolve;
}

function parseGenericArgument(definition: unknown, outer?: AliasResolver): IR {
	if (outer === undefined) {
		try {
			return parseDef(definition);
		} catch (error) {
			if (!(error instanceof OmpTypeError) || !error.message.includes('unknown keyword "this"')) throw error;
		}
	}
	let root: IR | undefined;
	const self: IR = {
		k: "alias",
		name: "this",
		resolve: () => {
			if (root === undefined || root === self) throw new OmpTypeError('"this" cannot be used as a root definition');
			return root;
		},
	};
	const resolve = ((name: string) => (name === "this" ? self : outer?.(name))) as AliasResolver;
	if (outer !== undefined) {
		resolve.hasGeneric = outer.hasGeneric;
		resolve.generic = outer.generic;
	} else {
		// The retry only exists to serve "this"; parses of this-free member
		// strings inside the definition may still share the string cache.
		markThisOnlyResolver(resolve);
	}
	root = parseDef(definition, resolve);
	if (root === self) throw new OmpTypeError('"this" cannot be used as a root definition');
	return root;
}

function genericBodyIR(

View on GitHub (pinned to 9690622007)

Solutions

  1. Give the root a concrete shape and use 'this' only nested inside it, e.g. type({ "next?": 'this' })
  2. Never use 'this' as the top-level definition string
  3. If a truly self-recursive value type is needed, structure it via properties/arrays that wrap 'this'

Example fix

// before
const T = type('this'); // throws
// after
const T = type({ value: 'number', next: 'this?' });
Defensive patterns

Strategy: validation

Validate before calling

function assertNotBareThis(def: unknown) {
  if (typeof def === 'string' && def.trim() === 'this') {
    throw new Error('root definition cannot be bare "this"; wrap it in a structure');
  }
}

Try / catch

try {
  const T = type(def);
} catch (err) {
  if (err instanceof OmpTypeError && err.message.includes('"this" cannot be used as a root definition')) {
    throw new Error(`Make "${String(def)}" a structure that nests "this" (e.g. { next: 'this?' })`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Parsing the definition 'this' itself (root === self), or referencing 'this' before root is assigned such that resolve() runs while root is undefined.

Common situations: Writing a recursive schema whose whole body is just 'this'; an editing slip where the actual structure was deleted leaving only the self-reference; generated code emitting a bare self-reference.

Related errors


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