{"id":"aea2b34b4dd73d9a","repo":"colinhacks/zod","slug":"a-discriminator-value-for-key-discriminator-c","errorCode":null,"errorMessage":"A discriminator value for key `${discriminator}` could not be extracted from all schema options","messagePattern":"A discriminator value for key `(.+?)` could not be extracted from all schema options","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/zod/src/v3/types.ts","lineNumber":3200,"sourceCode":"  static create<\n    Discriminator extends string,\n    Types extends readonly [\n      ZodDiscriminatedUnionOption<Discriminator>,\n      ...ZodDiscriminatedUnionOption<Discriminator>[],\n    ],\n  >(\n    discriminator: Discriminator,\n    options: Types,\n    params?: RawCreateParams\n  ): ZodDiscriminatedUnion<Discriminator, Types> {\n    // Get all the valid discriminator values\n    const optionsMap: Map<Primitive, Types[number]> = new Map();\n\n    // try {\n    for (const type of options) {\n      const discriminatorValues = getDiscriminator(type.shape[discriminator]);\n      if (!discriminatorValues.length) {\n        throw new Error(\n          `A discriminator value for key \\`${discriminator}\\` could not be extracted from all schema options`\n        );\n      }\n      for (const value of discriminatorValues) {\n        if (optionsMap.has(value)) {\n          throw new Error(`Discriminator property ${String(discriminator)} has duplicate value ${String(value)}`);\n        }\n\n        optionsMap.set(value, type);\n      }\n    }\n\n    return new ZodDiscriminatedUnion<\n      Discriminator,\n      // DiscriminatorValue,\n      Types\n    >({\n      typeName: ZodFirstPartyTypeKind.ZodDiscriminatedUnion,","sourceCodeStart":3182,"sourceCodeEnd":3218,"githubUrl":"https://github.com/colinhacks/zod/blob/912f0f51b0ced654d0069741e7160834dca742ee/packages/zod/src/v3/types.ts#L3182-L3218","documentation":"Thrown by z.discriminatedUnion when getDiscriminator returns no extractable literal value for one of the options. The discriminator field must resolve to a concrete primitive (literal string/number/boolean, a single-value enum, etc.) on every option so the union can dispatch at runtime.","triggerScenarios":"z.discriminatedUnion('type', [A, B]) where one option's `type` field is a plain z.string() (no literal), optional and missing, an unsupported type (e.g. z.any(), z.array()), or nested behind an intermediary that getDiscriminator cannot unwrap.","commonSituations":"Building a tagged union where one branch forgot to constrain the tag (used `type: z.string()` instead of `type: z.literal('a')`); renaming a tag literal and forgetting a branch; discriminator hidden under z.optional or z.default.","solutions":["On every option, set the discriminator field to a concrete literal: `type: z.literal('a')`.","If the tag is optional in some branch, decide on a default via z.literal and remove optionality at the discriminator key.","Verify the discriminator key string actually exists on each option's `.shape`."],"exampleFix":"// before\nz.discriminatedUnion('type', [\n  z.object({ type: z.string(), a: z.string() }), // no literal -> error\n  z.object({ type: z.literal('b'), b: z.number() }),\n]);\n\n// after\nz.discriminatedUnion('type', [\n  z.object({ type: z.literal('a'), a: z.string() }),\n  z.object({ type: z.literal('b'), b: z.number() }),\n]);","handlingStrategy":"validation","validationCode":"import { getDiscriminator } from \"zod\"; // or replicate\nfunction verifyDiscriminator(disc: string, options: z.ZodObject<any>[]) {\n  for (const o of options) {\n    const vals = o.shape[disc];\n    if (!vals || !('value' in vals._def) && vals._def.values == null) {\n      throw new Error(`Option missing literal discriminator '${disc}'`);\n    }\n  }\n}","typeGuard":"function hasLiteralDiscriminator<K extends string>(\n  o: z.ZodObject<any>,\n  key: K\n): boolean {\n  const f = (o.shape as any)[key];\n  return !!f && (f instanceof z.ZodLiteral || f instanceof z.ZodEnum || f instanceof z.ZodNativeEnum);\n}","tryCatchPattern":null,"preventionTips":["Always type the discriminator field as z.literal for each branch.","Unit-test discriminated unions at construction time.","Keep the discriminator non-optional and non-defaulted."],"tags":["discriminated-union","literal","v3"],"analyzedSha":"912f0f51b0ced654d0069741e7160834dca742ee","analyzedAt":"2026-08-03T17:41:55.908Z","schemaVersion":2}