can1357/oh-my-pi · error · OmpTypeError

Record key must be assignable to string or symbol

Error message

Record key must be assignable to string or symbol

What it means

`type.Record(key, value)` requires the key schema to be a string or symbol type, because object property keys in JavaScript must be PropertyKeys. Any other key type (number, boolean, union with non-string members, literal of a non-key type) is rejected at schema-construction time.

Source

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

						input: { k: "union", members: [element, array] },
						fn: value => (globalThis.Array.isArray(value) ? value : [value]),
						out: array,
					},
					[],
					{},
				);
			},
		},
		Record<const key, const value>(
			key: key,
			value: value,
		): FluentType<
			Record<Extract<InferDef<key>, PropertyKey>, InferDef<value>>,
			Record<Extract<InferDefIn<key>, PropertyKey>, InferDefIn<value>>
		> {
			const keyIR = parseDef(key);
			if (keyIR.k !== "string" && keyIR.k !== "symbol") {
				throw new OmpTypeError("Record key must be assignable to string or symbol");
			}
			const valueIR = parseDef(value);
			const ir: IR =
				keyIR.k === "symbol"
					? { k: "object", props: [], symbolIndex: valueIR, extras: "keep" }
					: { k: "object", props: [], index: valueIR, extras: "keep" };
			return makeType<
				Record<Extract<InferDef<key>, PropertyKey>, InferDef<value>>,
				Record<Extract<InferDefIn<key>, PropertyKey>, InferDefIn<value>>
			>(ir, [], {});
		},
		Partial<const definition>(
			definition: definition,
		): FluentType<Partial<InferDef<definition>>, Partial<InputObject<InferDefIn<definition>>>> {
			return makeType<Partial<InferDef<definition>>, Partial<InputObject<InferDefIn<definition>>>>(
				setObjectOptionality(parseDef(definition), true, "partial"),
				[],
				{},

View on GitHub (pinned to 9690622007)

Solutions

  1. Use a string key schema: `type.Record("string", value)`.
  2. For restricted keys use `"string.numeric"`-style or a string union of literals if the key type is `'a' | 'b'`.
  3. Wrap non-string key semantics manually: parse keys with `String(k)` before validation.

Example fix

// before
type.Record("number", "string")
// after
type.Record("string", "string")
Defensive patterns

Strategy: type-guard

Validate before calling

function isRecordKeyDef(def: unknown): boolean { return def === 'string' || def === 'symbol' || (typeof def === 'string' && /^'[^']+'$/.test(def)); }

Type guard

const isStringKey = (def: string): boolean => def === 'string' || def === 'symbol' || def === 'string.numeric';

Try / catch

try { const r = type.Record(keyDef, valueDef); } catch (e) { if (e instanceof OmpTypeError) fallbackToStringKey(); else throw e; }

Prevention

When it happens

Trigger: Calling `type.Record("number", "string")` or `type.Record("boolean | string", "string")` — the key IR parses to something other than `string` or `symbol`.

Common situations: Porting from Zod/TS where `Record<number, T>` is legal at the type level; omptype requires the key schema be a string type (numeric coercion is not modeled), so developers porting validators hit this.

Related errors


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