{"record":{"id":"1393b78db7dafc9e","repo":"can1357/oh-my-pi","slug":"optional-key-string-key-cannot-specify-a-defau","errorCode":null,"errorMessage":"optional key ${String(key)} cannot specify a default","messagePattern":"optional key (.+?) cannot specify a default","errorType":"exception","errorClass":"OmpTypeError","httpStatus":null,"severity":"error","filePath":"packages/omptype/src/ir.ts","lineNumber":1431,"sourceCode":"\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\") {\n\t\t\tconst parsed = parseStringDef(val, resolve);\n\t\t\tprop = { key, opt: parsed.optional, val: parsed.ir };\n\t\t\tif (parsed.hasDefault) {\n\t\t\t\tprop.def = parsed.def;\n\t\t\t\tprop.hasDefault = true;\n\t\t\t}\n\t\t} else if (Array.isArray(val) && val.length === 2 && val[1] === \"?\") {\n\t\t\tprop = { key, opt: true, val: parseDef(val[0], resolve) };\n\t\t} else if (Array.isArray(val) && val.length === 3 && val[1] === \"=\") {\n\t\t\tprop = {","sourceCodeStart":1413,"sourceCodeEnd":1449,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/omptype/src/ir.ts#L1413-L1449","documentation":"A property marked optional with the \"?\" marker cannot also declare a default value — the two are mutually exclusive in omptype's IR (optional means the key may be absent; a default means it is always materialized). parseObjectDefinition throws this when a parsed property has both opt and hasDefault set.","triggerScenarios":"Defining a property like \"id?:\" with a defaulted value form ([key, \"=\", value] or an embedded type with hasDefault) in parseObjectDefinition, i.e. opt === true while prop.hasDefault is true.","commonSituations":"Adding \"?\" to a property that previously had a default; auto-generating schemas from TS types where optional fields also carry defaults; misunderstanding that \"?\" plus default are redundant in ArkType-like DSLs.","solutions":["Drop the \"?\" marker and keep the default (the default already makes the key optional in effect)","Keep \"?\" and remove the default","If the field should always exist with a fallback, use the default-only form"],"exampleFix":"// before\ntype({ \"port?\": [\"=\", \"8080\"] })\n// after\ntype({ port: [\"=\", \"8080\"] }) // default implies optionality","handlingStrategy":"validation","validationCode":"function assertOptionalWithoutDefault(key, val) {\n  const isOptional = key.endsWith(\"?\") || key.endsWith(\"?:\");\n  const hasDefault = (Array.isArray(val) && val.length === 3 && val[1] === \"=\") || val?.hasDefault === true;\n  if (isOptional && hasDefault) throw new Error(`optional key ${key} cannot also have a default`);\n}","typeGuard":null,"tryCatchPattern":"try { const T = type(def); } catch (e) {\n  if (String(e.message).startsWith(\"optional key\")) {\n    // drop either the \"?\" marker or the default, then retry\n  } else throw e;\n}","preventionTips":["Treat a default as implying optionality; never add \"?\" to defaulted properties","When generating defs from TS types, skip emitting defaults for optional members","Document the \"?\"-xor-default rule in schema-authoring guidelines"],"tags":["omptype","schema-definition","optional","default-value"],"backgroundTag":"optional-key-default-conflict","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}