{"id":"1fb90ba5c11eae04","repo":"pydantic/pydantic","slug":"the-core-schema-type-choice-type-r-is-not-a-v","errorCode":null,"errorMessage":"The core schema type {choice[\"type\"]!r} is not a valid discriminated union variant.","messagePattern":"The core schema type (.+?) is not a valid discriminated union variant\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"pydantic/_internal/_discriminated_union.py","lineNumber":279,"sourceCode":"            choices_schemas = [v[0] if isinstance(v, tuple) else v for v in choice['choices'][::-1]]\n            self._choices_to_handle.extend(choices_schemas)\n        elif choice['type'] not in {\n            'model',\n            'typed-dict',\n            'tagged-union',\n            'lax-or-strict',\n            'dataclass',\n            'dataclass-args',\n            'definition-ref',\n        } and not _core_utils.is_function_with_inner_schema(choice):\n            # We should eventually handle 'definition-ref' as well\n            err_str = f'The core schema type {choice[\"type\"]!r} is not a valid discriminated union variant.'\n            if choice['type'] == 'list':\n                err_str += (\n                    ' If you are making use of a list of union types, make sure the discriminator is applied to the '\n                    'union type and not the list (e.g. `list[Annotated[<T> | <U>, Field(discriminator=...)]]`).'\n                )\n            raise TypeError(err_str)\n        else:\n            if choice['type'] == 'tagged-union' and self._is_discriminator_shared(choice):\n                # In this case, this inner tagged-union is compatible with the outer tagged-union,\n                # and its choices can be coalesced into the outer TaggedUnionSchema.\n                subchoices = [x for x in choice['choices'].values() if not isinstance(x, (str, int))]\n                # Reverse the choices list before extending the stack so that they get handled in the order they occur\n                self._choices_to_handle.extend(subchoices[::-1])\n                return\n\n            inferred_discriminator_values = self._infer_discriminator_values_for_choice(choice, source_name=None)\n            self._set_unique_choice_for_values(choice, inferred_discriminator_values)\n\n    def _is_discriminator_shared(self, choice: core_schema.TaggedUnionSchema) -> bool:\n        \"\"\"This method returns a boolean indicating whether the discriminator for the `choice`\n        is the same as that being used for the outermost tagged union. This is used to\n        determine whether this TaggedUnionSchema choice should be \"coalesced\" into the top level,\n        or whether it should be treated as a separate (nested) choice.\n        \"\"\"","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/pydantic/pydantic/blob/2e5f0e2b4218de31709f1cf9c5bc61ea97a68835/pydantic/_internal/_discriminated_union.py#L261-L297","documentation":"_handle_choice validates each union variant of a discriminated union. A choice is acceptable only if its core-schema type is in {model, typed-dict, tagged-union, lax-or-strict, dataclass, dataclass-args, definition-ref} or it is a function-with-inner-schema. Any other type (e.g. 'list', 'str', 'int', 'dict') is rejected with a TypeError naming the offending type, with an extra hint when the type is 'list'.","triggerScenarios":"Annotating a discriminated union whose variant is a bare primitive or container, e.g. Annotated[Union[Cat, Dog, str], Field(discriminator='kind')] where 'str' is not a model/typed-dict/dataclass. Also list[Union[...]] with the discriminator misplaced on the list (the error message hints at this).","commonSituations":"Adding a fallback primitive type to a discriminated union; misplacing Field(discriminator=...) on a list rather than on the inner union; using a discriminated union over non-model types.","solutions":["Ensure every union variant is a BaseModel, TypedDict, or dataclass (or a compatible wrapper).","If you have list[Union[Cat, Dog]], put the discriminator on the inner Union via Annotated: list[Annotated[Union[Cat, Dog], Field(discriminator='kind')]].","Remove primitive variants from the discriminated union or wrap them in a model/typed-dict."],"exampleFix":"# before\nlist[Union[Cat, Dog]]  with Field(discriminator='kind') on the list field -> error\n\n# after\nlist[Annotated[Union[Cat, Dog], Field(discriminator='kind')]]","handlingStrategy":"type-guard","validationCode":"ALLOWED_VARIANT_TYPES = {'model', 'typed-dict', 'tagged-union', 'lax-or-strict', 'dataclass', 'dataclass-args', 'definition-ref'}\n\ndef is_valid_union_variant(schema: dict) -> bool:\n    return schema.get('type') in ALLOWED_VARIANT_TYPES","typeGuard":"def is_discriminatable_variant(tp: type) -> bool:\n    from pydantic import BaseModel\n    from typing import is_typeddict\n    import dataclasses\n    return issubclass(tp, BaseModel) or is_typeddict(tp) or dataclasses.is_dataclass(tp)","tryCatchPattern":"try:\n    class M(BaseModel):\n        x: Annotated[Union[Cat, Dog], Field(discriminator='kind')]\nexcept TypeError as e:\n    if 'not a valid discriminated union variant' in str(e):\n        # ensure every variant is a model/typed-dict/dataclass\n        raise\n    raise","preventionTips":["Make every discriminated-union variant a BaseModel, TypedDict, or dataclass.","Place Field(discriminator=...) on the Union, not on a wrapping list.","Avoid mixing primitive types into a discriminated union."],"tags":["python","pydantic","discriminated-union","schema","typeerror","discriminator"],"analyzedSha":"2e5f0e2b4218de31709f1cf9c5bc61ea97a68835","analyzedAt":"2026-08-04T19:54:21.281Z","schemaVersion":2}