can1357/oh-my-pi · error · OmpTypeError

generic parameters must be names or [name, constraint] pairs

Error message

generic parameters must be names or [name, constraint] pairs

What it means

When declaring a runtime generic via `type.generic(...)`, each parameter must be either a plain name string or a two-element array of `[name, constraintDefinition]`. Anything else (numbers, objects, nested arrays, empty arrays, non-string first element) cannot be interpreted as a parameter declaration and throws.

Source

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

		};
	}

	type GenericParameterSpec = string | readonly [name: string, constraint: unknown];

	/** Build a generic directly from an angle-bracket declaration. */
	export function generic<const definition>(parameters: `<${string}>`, definition: definition): Generic;
	/** Build a curried generic from named, optionally constrained parameters. */
	export function generic(...parameters: readonly GenericParameterSpec[]): GenericBuilder;
	export function generic(...arguments_: readonly (GenericParameterSpec | unknown)[]): Generic | GenericBuilder {
		if (arguments_.length === 2 && typeof arguments_[0] === "string" && arguments_[0].trimStart().startsWith("<")) {
			return createRuntimeGeneric(parseGenericParameters(arguments_[0]), arguments_[1]);
		}
		const parameters: GenericParameter[] = arguments_.map(parameter => {
			if (typeof parameter === "string") return { name: parameter.trim() };
			if (Array.isArray(parameter) && typeof parameter[0] === "string") {
				return { name: parameter[0].trim(), constraintDef: parameter[1] };
			}
			throw new OmpTypeError("generic parameters must be names or [name, constraint] pairs");
		});
		validateGenericParameters(parameters);
		return (definition: unknown) => createRuntimeGeneric(parameters, definition);
	}

	/** Untyped builder for runtime-assembled definitions. */
	export function raw(def: unknown): BaseType {
		return makeType(parseDef(def), [], {}) as unknown as BaseType;
	}

	/**
	 * Return a validation-only schema that emits `json` verbatim — even when
	 * embedded in an object, array, or union.
	 *
	 * A `.toJsonSchema()` method override cannot survive nesting: a parent schema
	 * emits each child's IR directly and never calls the child's method, so the
	 * override silently disappears from the wire schema. This stores the override
	 * on the IR instead.

View on GitHub (pinned to 9690622007)

Solutions

  1. Pass plain strings: `type.generic("T", "U", definition)`.
  2. For constrained parameters pass `["T", constraint]` pairs: `type.generic(["T", "string"], definition)`.
  3. Validate/normalize any config-driven parameter list to strings or [string, def] pairs before calling.

Example fix

// before
type.generic({ name: "T" }, "T[]")
// after
type.generic("T", "T[]")
Defensive patterns

Strategy: validation

Validate before calling

const validParam = (p: unknown) => typeof p === 'string' || (Array.isArray(p) && typeof p[0] === 'string' && p.length === 2);

Type guard

type GenericParam = string | [string, unknown]; const isGenericParam = (p: unknown): p is GenericParam => typeof p === 'string' || (Array.isArray(p) && typeof p[0] === 'string');

Try / catch

try { const g = type.generic(...params, definition); } catch (e) { if (e instanceof OmpTypeError) normalizeParams(params); else throw e; }

Prevention

When it happens

Trigger: Calling `type.generic(1, "T")`, `type.generic({ name: "T" })`, or `type.generic([])`; also `type.generic(["T"], ...)` where the outer argument was meant to be one parameter but arrived as a malformed pair like `[123, ...]`.

Common situations: Programmatically building generic declarations from config/JSON where parameters were stored as objects; porting ArkType keyword-style generic syntax incorrectly; typos leaving a parameter array with a non-string first slot.

Related errors


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