{"id":"c97358a769ab77be","repo":"colinhacks/zod","slug":"invalid-discriminated-union-option-at-index-def-c97358","errorCode":null,"errorMessage":"Invalid discriminated union option at index \"${def.options.indexOf(o)}\"","messagePattern":"Invalid discriminated union option at index \"(.+?)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/zod/src/v4/core/schemas.ts","lineNumber":2390,"sourceCode":"        if (!pv || Object.keys(pv).length === 0)\n          throw new Error(`Invalid discriminated union option at index \"${def.options.indexOf(option)}\"`);\n        for (const [k, v] of Object.entries(pv!)) {\n          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,","sourceCodeStart":2372,"sourceCodeEnd":2408,"githubUrl":"https://github.com/colinhacks/zod/blob/912f0f51b0ced654d0069741e7160834dca742ee/packages/zod/src/v4/core/schemas.ts#L2372-L2408","documentation":"Thrown while building the discriminator lookup map in `$ZodDiscriminatedUnion` (the cached `disc` function). The option at the given index is an object, but it has no values registered for the specific discriminator key (`def.discriminator`). In other words, the option is discriminable in general but does not actually carry the discriminator field that the union was declared with, so it cannot be matched during parsing.","triggerScenarios":"Declaring `z.discriminatedUnion('kind', [A, B])` where the discriminator key is `'kind'` but one of A/B has no `kind` field, or its `kind` field is a non-literal type like `z.string()` (which yields no discrete propValues). Also: a typo in the discriminator string, or renaming the field on one option but not the others.","commonSituations":"Renaming a discriminator field on one variant and forgetting the others; copy-pasting variants and changing the field name only in the copy; using `z.string()` for the discriminator instead of `z.literal`/`z.enum`.","solutions":["Check the option at the reported index and add the discriminator field with a literal/enum value, e.g. `kind: z.literal('circle')`.","Verify the discriminator string passed to `z.discriminatedUnion(discriminator, options)` exactly matches the field name present on EVERY option.","Make the discriminator field an enum or literal on each option (a plain `z.string()` produces no discrete values and is not discriminable)."],"exampleFix":"// before\nconst Shape = z.discriminatedUnion('kind', [\n  z.object({ kind: z.literal('circle'), radius: z.number() }),\n  z.object({ shape: z.literal('square'), side: z.number() }), // wrong key\n]);\n\n// after\nconst Shape = z.discriminatedUnion('kind', [\n  z.object({ kind: z.literal('circle'), radius: z.number() }),\n  z.object({ kind: z.literal('square'), side: z.number() }),\n]);","handlingStrategy":"validation","validationCode":"function assertAllHaveDiscriminator(discriminator, options) {\n  options.forEach((opt, i) => {\n    const pv = opt._zod?.propValues;\n    if (!pv || !pv[discriminator] || pv[discriminator].size === 0) {\n      throw new Error(`Option ${i} missing discriminator \"${discriminator}\"`);\n    }\n  });\n}","typeGuard":"function hasDiscriminatorValue(s, key): boolean {\n  const pv = s._zod?.propValues;\n  return !!pv && pv[key] instanceof Set && pv[key].size > 0;\n}","tryCatchPattern":"try {\n  const U = z.discriminatedUnion(discKey, options);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('Invalid discriminated union option')) {\n    // identify the option missing the discriminator key and fix its shape\n  }\n  throw e;\n}","preventionTips":["Keep the discriminator key name in a shared constant and reference it on every option.","Type each option's discriminator field as z.literal(...) or z.enum([...]), never a bare z.string().","Add a test that parses one example per option to surface definition errors."],"tags":["discriminated-union","schema-definition","validation"],"analyzedSha":"912f0f51b0ced654d0069741e7160834dca742ee","analyzedAt":"2026-08-03T17:41:55.908Z","schemaVersion":2}