can1357/oh-my-pi · error · OmpTypeError

duplicate generic parameter "${parameter.name}"

Error message

duplicate generic parameter "${parameter.name}"

What it means

validateGenericParameters() rejects duplicate generic parameter names by tracking names in a Set and throwing OmpTypeError on a repeat. Duplicated placeholders are ambiguous — the body could not tell which argument to substitute where — so they are errors at declaration time.

Source

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

}

/** 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 = "";
			continue;
		}

View on GitHub (pinned to 9690622007)

Solutions

  1. Rename one of the duplicated parameters to a distinct identifier
  2. If merging parameter lists programmatically, deduplicate before joining (e.g. new Set(parts))
  3. Review copy/pasted declarations for leftover repeated placeholders

Example fix

// before
const T = generic('<T, T>', 'record<T, T[]>'); // throws
// after
const T = generic('<K, V>', 'record<K, V[]>');
Defensive patterns

Strategy: validation

Validate before calling

function assertUniqueParams(names: readonly string[]) {
  const dupes = names.filter((n, i) => names.indexOf(n) !== i);
  if (dupes.length) throw new Error(`duplicate generic parameters: ${[...new Set(dupes)].join(', ')}`);
}

Try / catch

try {
  const G = generic(decl, body);
} catch (err) {
  if (err instanceof OmpTypeError && err.message.includes('duplicate generic parameter')) {
    const name = err.message.match(/"(.*)"/)?.[1];
    throw new Error(`Rename the repeated parameter "${name}" in "${decl}"`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Declaring a generic with the same parameter twice, e.g. generic('<T, T>', ...) or generic('<K, V, K>', ...), including duplicates introduced by string splitting when the declaration is built dynamically.

Common situations: Copy/paste when extending a generic's parameter list; concatenating parameter strings from two sources that both use 'T'; typos where an intended distinct name was never changed.

Related errors


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