pydantic/pydantic · error · PydanticUserError

discriminator-alias-type

discriminator-alias-type

Error message

Alias {alias!r} is not supported in a discriminated union

What it means

Pydantic raises this PydanticUserError (code 'discriminator-alias-type') when the discriminator field on a union member has a validation_alias that is not a plain string — for example an AliasChoices list, an AliasPath tuple, or any tuple/list-valued alias. The discriminated-union machinery at _infer_discriminator_values_for_field (line 417-421) reads field.get('validation_alias', self.discriminator) and requires it to be a str so it can be used as a single lookup key in the tagged-union schema. Complex alias paths cannot serve as a discriminator key.

Source

Thrown at pydantic/_internal/_discriminated_union.py:419

        self, choice: core_schema.DataclassArgsSchema, source_name: str | None = None
    ) -> list[str | int]:
        source = 'DataclassArgs' if source_name is None else f'Dataclass {source_name!r}'
        for field in choice['fields']:
            if field['name'] == self.discriminator:
                break
        else:
            raise PydanticUserError(
                f'{source} needs a discriminator field for key {self.discriminator!r}', code='discriminator-no-field'
            )
        return self._infer_discriminator_values_for_field(field, source)

    def _infer_discriminator_values_for_field(self, field: CoreSchemaField, source: str) -> list[str | int]:
        if field['type'] == 'computed-field':
            # This should never occur as a discriminator, as it is only relevant to serialization
            return []
        alias = field.get('validation_alias', self.discriminator)
        if not isinstance(alias, str):
            raise PydanticUserError(
                f'Alias {alias!r} is not supported in a discriminated union', code='discriminator-alias-type'
            )
        if self._discriminator_alias is None:
            self._discriminator_alias = alias
        elif self._discriminator_alias != alias:
            raise PydanticUserError(
                f'Aliases for discriminator {self.discriminator!r} must be the same '
                f'(got {alias}, {self._discriminator_alias})',
                code='discriminator-alias',
            )
        return self._infer_discriminator_values_for_inner_schema(field['schema'], source)

    def _infer_discriminator_values_for_inner_schema(
        self, schema: core_schema.CoreSchema, source: str
    ) -> list[str | int]:
        """When inferring discriminator values for a field, we typically extract the expected values from a literal
        schema. This function does that, but also handles nested unions and defaults.
        """

View on GitHub (pinned to 2e5f0e2b42)

Solutions

  1. Use a plain string validation_alias on the discriminator field: Field(validation_alias='kind').
  2. If the tag lives nested in your input, flatten the input before validation or use a pre-validator to hoist the value to the top level.
  3. Remove the alias entirely so the discriminator field uses its Python attribute name as the lookup key.
  4. Consider a callable Discriminator if the tag must be extracted via custom logic.

Example fix

// before
class Cat(BaseModel):
    pet_type: Literal['cat'] = Field(validation_alias=AliasPath('header', 'kind'))

// after
class Cat(BaseModel):
    pet_type: Literal['cat'] = Field(validation_alias='kind')
Defensive patterns

Strategy: validation

Validate before calling

from pydantic.fields import AliasPath, AliasChoices

def check_discriminator_alias_simple(model_cls, field_name: str) -> None:
    info = model_cls.model_fields[field_name]
    alias = info.validation_alias
    if alias is not None and not isinstance(alias, str):
        raise TypeError(f'{model_cls.__name__}.{field_name} has non-string alias {alias!r}')

check_discriminator_alias_simple(Cat, 'pet_type')

Type guard

def is_plain_alias(alias) -> bool:
    return alias is None or isinstance(alias, str)

Try / catch

from pydantic import PydanticUserError

try:
    Pet.model_rebuild()
except PydanticUserError as e:
    if e.code == 'discriminator-alias-type':
        # replace AliasPath/AliasChoices on the discriminator with a plain str alias
        ...

Prevention

When it happens

Trigger: Annotating the discriminator field with Field(validation_alias=AliasPath('meta', 'kind')) or Field(validation_alias=AliasChoices('kind', 'type')) inside a member of a discriminated union. Also occurs when an alias_generator produces a non-string for the discriminator field name.

Common situations: Trying to read the discriminator value from a nested location in incoming JSON (e.g. AliasPath) rather than the top level. Reusing a model that has a generic alias generator that returns tuples for some fields.

Related errors


AI-assisted analysis of pydantic/pydantic@2e5f0e2b42 (2026-08-04). Data as JSON: /data/errors/f1e2070615e3a2df.json. Report an issue: GitHub.