{"record":{"id":"1bef32b746031a62","repo":"can1357/oh-my-pi","slug":"duplicate-object-key-string-key","errorCode":null,"errorMessage":"duplicate object key ${String(key)}","messagePattern":"duplicate object key (.+?)","errorType":"exception","errorClass":"OmpTypeError","httpStatus":null,"severity":"error","filePath":"packages/omptype/src/ir.ts","lineNumber":1421,"sourceCode":"\t\t\t\t\t\tkey,\n\t\t\t\t\t\topt,\n\t\t\t\t\t\tval: embed(val),\n\t\t\t\t\t\tdef: val.hasDefaultOutput ? val.defaultOutput : val.defaultValue,\n\t\t\t\t\t\tdefFactory: typeof val.defaultValue === \"function\",\n\t\t\t\t\t\thasDefault: true,\n\t\t\t\t\t\tdefValidated: val.hasDefaultOutput,\n\t\t\t\t\t}\n\t\t\t\t: { key, opt, val: embed(val) };\n\t\t} else {\n\t\t\tprop = {\n\t\t\t\tkey,\n\t\t\t\topt,\n\t\t\t\tval: isObjectDefinition(val) ? parseObjectDefinition(val, resolve) : parseDef(val, resolve),\n\t\t\t};\n\t\t}\n\t\tif (key !== originalKey) {\n\t\t\tif (!spreadKeys?.has(key) && props.some(candidate => candidate.key === key)) {\n\t\t\t\tthrow new OmpTypeError(`duplicate object key ${String(key)}`);\n\t\t\t}\n\t\t\tif (normalizedKey === undefined) normalizedKey = key;\n\t\t\telse {\n\t\t\t\tnormalizedKeys ??= [normalizedKey];\n\t\t\t\tnormalizedKeys.push(key);\n\t\t\t}\n\t\t} else if (!spreadKeys?.has(key) && (key === normalizedKey || normalizedKeys?.includes(key))) {\n\t\t\tthrow new OmpTypeError(`duplicate object key ${String(key)}`);\n\t\t}\n\t\tif (opt && prop.hasDefault) throw new OmpTypeError(`optional key ${String(key)} cannot specify a default`);\n\t\tif (simple && (prop.hasDefault || !isSimpleIR(prop.val))) simple = false;\n\t\taddObjectProp(props, spreadKeys, prop);\n\t}\n\tfor (const key of Object.getOwnPropertySymbols(def)) {\n\t\tif (!Object.prototype.propertyIsEnumerable.call(def, key)) continue;\n\t\tconst val = def[key];\n\t\tlet prop: PropIR;\n\t\tif (typeof val === \"string\") {","sourceCodeStart":1403,"sourceCodeEnd":1439,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/omptype/src/ir.ts#L1403-L1439","documentation":"When an object definition key is normalized (e.g. quoted, optional marker, or alias-resolved to a different canonical key) and the normalized key collides with an already-declared property that did not come from a spread, parseObjectDefinition rejects it as a duplicate. This prevents two entries silently merging or shadowing each other in the parsed IR.","triggerScenarios":"Declaring two entries in one object definition whose normalized keys are equal (e.g. \"name\" and \"'name'\" both present, or a quoted key and its unquoted equivalent) while the key was not introduced via spread — checked via props.some(candidate => candidate.key === key) in the key !== originalKey branch.","commonSituations":"Mixing quoted and unquoted spellings of the same property; alias resolution mapping two different source keys onto the same canonical name; merging hand-written definitions that both include the same key.","solutions":["Remove one of the duplicate property entries","Use spread to intentionally combine definitions (spread keys bypass this duplicate check)","Ensure each source key normalizes to a unique canonical key"],"exampleFix":"// before\ntype({ name: \"string\", \"'name'\": \"number\" }) // duplicate key \"name\"\n// after\ntype({ name: \"string\" })","handlingStrategy":"validation","validationCode":"function assertNoNormalizedDuplicates(def) {\n  const norm = (k) => k.replace(/^'+|'+$/g, \"\");\n  const seen = new Set();\n  for (const k of Object.keys(def)) {\n    const n = norm(k);\n    if (seen.has(n)) throw new Error(`duplicate key after normalization: ${n}`);\n    seen.add(n);\n  }\n}","typeGuard":null,"tryCatchPattern":"try { const T = type(def); } catch (e) {\n  if (String(e.message).startsWith(\"duplicate object key\")) {\n    // dedupe def entries or switch to explicit spreads, then rebuild\n  } else throw e;\n}","preventionTips":["Avoid mixing quoted and unquoted spellings of the same property","When generating definitions programmatically, key an intermediate Map so duplicates collapse or fail early","Prefer explicit spreads over concatenating definition objects"],"tags":["omptype","schema-definition","duplicate-key"],"backgroundTag":"duplicate-object-key","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}