can1357/oh-my-pi · error · OmpTypeError

generic expects ${parameters.length} arguments (received ${a

Error message

generic expects ${parameters.length} arguments (received ${arguments_.length})

What it means

instantiateIR() checks argument count against the declared generic parameter count and throws OmpTypeError on mismatch. Generics are exact-arity: you must supply one type argument per declared parameter when instantiating.

Source

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

	definition: unknown,
	outer?: AliasResolver,
	validateBody = true,
): RuntimeGeneric {
	const constraintResolve = ((name: string) => outer?.(name)) as AliasResolver;
	constraintResolve.hasGeneric = outer?.hasGeneric;
	constraintResolve.generic = outer?.generic;
	validateGenericParameters(parameters);
	const placeholders = parameters.map(parameter =>
		parameter.constraintDef === undefined
			? ({ k: "unknown" } as IR)
			: parseDef(parameter.constraintDef, constraintResolve),
	);
	if (validateBody) genericBodyIR(parameters, definition, placeholders, outer);
	const meta: GenericMeta = {
		parameters,
		instantiateIR(arguments_) {
			if (arguments_.length !== parameters.length) {
				throw new OmpTypeError(`generic expects ${parameters.length} arguments (received ${arguments_.length})`);
			}
			for (let index = 0; index < parameters.length; index++) {
				const parameter = parameters[index];
				if (parameter.constraintDef === undefined) continue;
				const constraint = parseDef(parameter.constraintDef, constraintResolve);
				if (!isSubtype(arguments_[index], constraint)) {
					throw new OmpTypeError(`${parameter.name} must be assignable to its constraint`);
				}
			}
			return genericBodyIR(parameters, definition, arguments_, outer);
		},
	};
	const generic = Object.assign(
		(...arguments_: readonly unknown[]) =>
			makeType(
				meta.instantiateIR(arguments_.map(argument => parseGenericArgument(argument, outer))),
				EMPTY_STEPS,
				EMPTY_META,

View on GitHub (pinned to 9690622007)

Solutions

  1. Pass exactly as many type arguments as declared parameters: G('string', 'number') for '<T, U>'
  2. Update all instantiation sites after changing the generic's parameter list
  3. Inspect the error's received count to see how many arguments actually arrived and fix the spread
  4. For optional parameters, provide an explicit concrete type instead of omitting the argument

Example fix

// before
const G = generic('<K, V>', 'record<K, V>');
const r = G('string'); // throws: expects 2
// after
const r = G('string', 'number');
Defensive patterns

Strategy: type-guard

Validate before calling

function assertArity(params: readonly unknown[], declared: number) {
  if (params.length !== declared) {
    throw new Error(`generic expects ${declared} arguments (received ${params.length})`);
  }
}

Type guard

function hasExactArity<const N extends number>(args: readonly unknown[], n: N): args is { length: N } & readonly unknown[] {
  return args.length === n;
}

Try / catch

try {
  const inst = G(...typeArgs);
} catch (err) {
  if (err instanceof OmpTypeError && /generic expects \d+ arguments/.test(err.message)) {
    throw new Error(`Check call sites of generic "${genericName}": ${err.message}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling the generic with too few or too many type arguments, e.g. generic('<K, V>', ...) instantiated with only one argument, or zero arguments via .instantiate()/calling without args.

Common situations: Arity changed after refactoring the parameter list but call sites weren't updated; spreading an array of arguments that is empty or mis-collected; forgetting that a two-parameter generic needs both arguments.

Related errors


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