{"record":{"id":"7ef04c34aa827173","repo":"can1357/oh-my-pi","slug":"record-key-must-be-assignable-to-string-or-symbol","errorCode":null,"errorMessage":"Record key must be assignable to string or symbol","messagePattern":"Record key must be assignable to string or symbol","errorType":"exception","errorClass":"OmpTypeError","httpStatus":null,"severity":"error","filePath":"packages/omptype/src/type.ts","lineNumber":3495,"sourceCode":"\t\t\t\t\t\tinput: { k: \"union\", members: [element, array] },\n\t\t\t\t\t\tfn: value => (globalThis.Array.isArray(value) ? value : [value]),\n\t\t\t\t\t\tout: array,\n\t\t\t\t\t},\n\t\t\t\t\t[],\n\t\t\t\t\t{},\n\t\t\t\t);\n\t\t\t},\n\t\t},\n\t\tRecord<const key, const value>(\n\t\t\tkey: key,\n\t\t\tvalue: value,\n\t\t): FluentType<\n\t\t\tRecord<Extract<InferDef<key>, PropertyKey>, InferDef<value>>,\n\t\t\tRecord<Extract<InferDefIn<key>, PropertyKey>, InferDefIn<value>>\n\t\t> {\n\t\t\tconst keyIR = parseDef(key);\n\t\t\tif (keyIR.k !== \"string\" && keyIR.k !== \"symbol\") {\n\t\t\t\tthrow new OmpTypeError(\"Record key must be assignable to string or symbol\");\n\t\t\t}\n\t\t\tconst valueIR = parseDef(value);\n\t\t\tconst ir: IR =\n\t\t\t\tkeyIR.k === \"symbol\"\n\t\t\t\t\t? { k: \"object\", props: [], symbolIndex: valueIR, extras: \"keep\" }\n\t\t\t\t\t: { k: \"object\", props: [], index: valueIR, extras: \"keep\" };\n\t\t\treturn makeType<\n\t\t\t\tRecord<Extract<InferDef<key>, PropertyKey>, InferDef<value>>,\n\t\t\t\tRecord<Extract<InferDefIn<key>, PropertyKey>, InferDefIn<value>>\n\t\t\t>(ir, [], {});\n\t\t},\n\t\tPartial<const definition>(\n\t\t\tdefinition: definition,\n\t\t): FluentType<Partial<InferDef<definition>>, Partial<InputObject<InferDefIn<definition>>>> {\n\t\t\treturn makeType<Partial<InferDef<definition>>, Partial<InputObject<InferDefIn<definition>>>>(\n\t\t\t\tsetObjectOptionality(parseDef(definition), true, \"partial\"),\n\t\t\t\t[],\n\t\t\t\t{},","sourceCodeStart":3477,"sourceCodeEnd":3513,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/omptype/src/type.ts#L3477-L3513","documentation":"`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.","triggerScenarios":"Calling `type.Record(\"number\", \"string\")` or `type.Record(\"boolean | string\", \"string\")` — the key IR parses to something other than `string` or `symbol`.","commonSituations":"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.","solutions":["Use a string key schema: `type.Record(\"string\", value)`.","For restricted keys use `\"string.numeric\"`-style or a string union of literals if the key type is `'a' | 'b'`.","Wrap non-string key semantics manually: parse keys with `String(k)` before validation."],"exampleFix":"// before\ntype.Record(\"number\", \"string\")\n// after\ntype.Record(\"string\", \"string\")","handlingStrategy":"type-guard","validationCode":"function isRecordKeyDef(def: unknown): boolean { return def === 'string' || def === 'symbol' || (typeof def === 'string' && /^'[^']+'$/.test(def)); }","typeGuard":"const isStringKey = (def: string): boolean => def === 'string' || def === 'symbol' || def === 'string.numeric';","tryCatchPattern":"try { const r = type.Record(keyDef, valueDef); } catch (e) { if (e instanceof OmpTypeError) fallbackToStringKey(); else throw e; }","preventionTips":["Always use 'string' (or 'symbol') as the key schema in type.Record","Remember Record<number, T> from TS/Zod must become a string-keyed record in omptype","Centralize record-key definitions in a constant to avoid drift"],"tags":["schema","record","property-key","validation"],"backgroundTag":"invalid-record-key-type","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}