can1357/oh-my-pi · error · OmpTypeError

invalid generic parameter "${parameter.name}"

Error message

invalid generic parameter "${parameter.name}"

What it means

validateGenericParameters() enforces that every generic parameter name matches /^[A-Za-z-$]\w*$/ — a valid identifier. A parameter name that is empty, starts with a digit, contains punctuation/spaces, or is otherwise not an identifier throws OmpTypeError. Generic parameters must be usable as placeholder names inside the definition body.

Source

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

interface RuntimeGeneric extends Generic {
	readonly [GENERIC_META]: GenericMeta;
}

/** Schema arguments passed to a callback-bodied runtime generic. */
export interface GenericArguments {
	readonly [name: string]: BaseType;
}

export interface GenericBuilder {
	(definition: (arguments_: GenericArguments) => unknown, hkt?: unknown): Generic;
	(definition: unknown, hkt?: unknown): Generic;
}

function validateGenericParameters(parameters: readonly GenericParameter[]): void {
	const names = new Set<string>();
	for (const parameter of parameters) {
		if (!/^[A-Za-z_$]\w*$/.test(parameter.name)) {
			throw new OmpTypeError(`invalid generic parameter "${parameter.name}"`);
		}
		if (names.has(parameter.name)) throw new OmpTypeError(`duplicate generic parameter "${parameter.name}"`);
		names.add(parameter.name);
	}
	if (parameters.length === 0) throw new OmpTypeError("generic declarations require at least one parameter");
}

function parseGenericParameters(source: string): GenericParameter[] {
	const trimmed = source.trim();
	const body = trimmed.startsWith("<") && trimmed.endsWith(">") ? trimmed.slice(1, -1) : trimmed;
	const parts: string[] = [];
	let start = 0;
	let depth = 0;
	let quote = "";
	for (let index = 0; index < body.length; index++) {
		const char = body[index];
		if (quote !== "") {
			if (char === quote && body[index - 1] !== "\\") quote = "";

View on GitHub (pinned to 9690622007)

Solutions

  1. Rename the parameter to a valid identifier: letters, digits, underscore, or $, not starting with a digit
  2. Check for stray characters (spaces, angle brackets left inside, punctuation) in the generic parameter list
  3. If constructing the declaration dynamically, validate/escape the name before interpolation
  4. Ensure the parameter list is not empty or malformed so no empty-string name reaches validation

Example fix

// before
const T = generic('<1st-Type>', 'array<1st-Type>'); // throws
// after
const T = generic('<Type1>', 'array<Type1>');
Defensive patterns

Strategy: validation

Validate before calling

const IDENT = /^[A-Za-z_$]\w*$/;
function assertValidParamName(name: string) {
  if (!IDENT.test(name)) throw new Error(`generic parameter name invalid: ${name}`);
}

Type guard

function isValidGenericName(name: string): boolean {
  return /^[A-Za-z_$]\w*$/.test(name);
}

Try / catch

try {
  const G = generic(decl, body);
} catch (err) {
  if (err instanceof OmpTypeError && err.message.includes('invalid generic parameter')) {
    console.error(`Fix generic declaration "${decl}": parameter names must be identifiers`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Declaring a generic like generic('<T!>', 'T[]') or '<0T>', '<foo bar>', or an empty '<>' — parseGenericParameters feeds raw names into validation and any non-identifier name fails the regex.

Common situations: Typos in generic declarations; copying a string type name into a parameter position; building generic names programmatically and interpolating invalid characters; trailing commas or whitespace producing empty names.

Related errors


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