{"record":{"id":"d14797bee0f9e7a2","repo":"colinhacks/zod","slug":"duplicate-discriminator-value-string-v","errorCode":null,"errorMessage":"Duplicate discriminator value \"${String(v)}\"","messagePattern":"Duplicate discriminator value \"(.+?)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/zod/src/v4/core/schemas.ts","lineNumber":2410,"sourceCode":"          if (!propValues[k]) propValues[k] = new Set();\n          for (const val of v) {\n            propValues[k].add(val);\n          }\n        }\n      }\n      return propValues;\n    });\n\n    const disc = util.cached(() => {\n      const opts = def.options as $ZodTypeDiscriminable[];\n      const map: Map<util.Primitive, $ZodType> = new Map();\n      for (const o of opts) {\n        const values = o._zod.propValues?.[def.discriminator];\n        if (!values || values.size === 0)\n          throw new Error(`Invalid discriminated union option at index \"${def.options.indexOf(o)}\"`);\n        for (const v of values) {\n          if (map.has(v)) {\n            throw new Error(`Duplicate discriminator value \"${String(v)}\"`);\n          }\n          map.set(v, o);\n        }\n      }\n      return map;\n    });\n\n    inst._zod.parse = (payload, ctx) => {\n      const input = payload.value;\n      if (!util.isObject(input)) {\n        payload.issues.push({\n          code: \"invalid_type\",\n\n          expected: \"object\",\n          input,\n          inst,\n        });\n        return payload;","sourceCodeStart":2392,"sourceCodeEnd":2428,"githubUrl":"https://github.com/colinhacks/zod/blob/2d90846af918af9602e088812d63a035d47cdbe4/packages/zod/src/v4/core/schemas.ts#L2392-L2428","documentation":"Thrown while building the discriminator map of a discriminated union when map.has(v) is already true for a value v produced by the current option's propValues. Each discriminator value must uniquely route to a single option; two options claiming the same literal at the discriminator key would make dispatch ambiguous, so construction aborts with the offending value (coerced via String(v)).","triggerScenarios":"Two options in z.discriminatedUnion(\"type\", [...]) both declaring z.literal(\"a\") at the \"type\" key; overlapping z.enum() sets across options that share a value; copy-pasting an option and forgetting to change its discriminator literal; discriminator literals computed dynamically that collide.","commonSituations":"Refactoring union members by cloning schemas; merging two previously-separate discriminated unions whose literals happen to overlap; enums that grow to include a value already used by another branch; casing issues (\"Active\" vs \"active\") that look distinct but collide after normalization elsewhere.","solutions":["Assign a unique literal value at the discriminator key for each option.","Audit overlapping z.enum() members and remove duplicates across options.","If two options legitimately share the same discriminator value, merge them into a single option or use z.union() instead.","Add a unit test asserting the set of discriminator values has no duplicates."],"exampleFix":"// before\nconst U = z.discriminatedUnion(\"type\", [\n  z.object({ type: z.literal(\"a\"), x: z.number() }),\n  z.object({ type: z.literal(\"a\"), y: z.string() }), // duplicate \"a\"\n]);\n// after\nconst U = z.discriminatedUnion(\"type\", [\n  z.object({ type: z.literal(\"a\"), x: z.number() }),\n  z.object({ type: z.literal(\"b\"), y: z.string() }),\n]);","handlingStrategy":"validation","validationCode":"function buildDiscUnion(disc: string, options: z.ZodObject[]) {\n  const seen = new Set<unknown>();\n  for (const o of options) {\n    for (const v of ((o as any)._zod.propValues?.[disc] ?? []) as unknown[]) {\n      if (seen.has(v)) throw new Error(`Duplicate discriminator value: ${String(v)}`);\n      seen.add(v);\n    }\n  }\n  return z.discriminatedUnion(disc, options);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Assign unique literals at the discriminator key for each option.","Unit-test the discriminator value set for uniqueness.","Audit overlapping z.enum() members across options during code review."],"tags":["discriminated-union","schema-construction","discriminator","duplicate"],"backgroundTag":null,"analyzedSha":"2d90846af918af9602e088812d63a035d47cdbe4","analyzedAt":"2026-08-11T01:21:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}