-
-
Notifications
You must be signed in to change notification settings - Fork 8.5k
Description
Discussed in #14495
Originally posted by atlasale December 11, 2025
First Check
- I added a very descriptive title here.
- I used the GitHub search to find a similar question and didn't find it.
- I searched the FastAPI documentation, with the integrated search.
- I already searched in Google "How to X in FastAPI" and didn't find any information.
- I already read and followed all the tutorial in the docs and didn't find an answer.
- I already checked if it is not related to FastAPI but to Pydantic.
- I already checked if it is not related to FastAPI but to Swagger UI.
- I already checked if it is not related to FastAPI but to ReDoc.
Commit to Help
- I commit to help with one of those options 👆
Example Code
from typing import Annotated, Union
from pydantic import BaseModel, Tag, Discriminator
from fastapi import FastAPI, Body
class Cat(BaseModel):
pet_type: str = "cat"
meows: int
class Dog(BaseModel):
pet_type: str = "dog"
barks: float
def get_pet_type(v):
if isinstance(v, dict):
return v.get("pet_type", "")
return getattr(v, "pet_type", "")
# Define discriminated union
Pet = Annotated[
Union[
Annotated[Cat, Tag("cat")],
Annotated[Dog, Tag("dog")]
],
Discriminator(get_pet_type)
]
app = FastAPI()
# ✅ THIS WORKS in 0.124.1+
@app.post("/pet/works")
async def create_pet_works(pet: Pet = Body(...)):
return pet
# ❌ THIS BREAKS in 0.124.1+ (worked in 0.124.0)
@app.post("/pet/broken")
async def create_pet_broken(pet: Annotated[Pet, Body(...)]):
return petDescription
I'm experiencing a breaking change when upgrading from FastAPI 0.124.0 to
0.124.1/0.124.2.
What works:
- FastAPI 0.124.0 - Both endpoint patterns work correctly
- FastAPI 0.124.1+ - Only pet: Pet = Body(...) works
What breaks:
- FastAPI 0.124.1+ - The pattern pet: Annotated[Pet, Body(...)] fails
with:
pydantic.errors.PydanticUserError: `Tag` not provided for choice {
'type': 'tagged-union',
'choices': {
'cat': {'type': 'definition-ref', 'metadata':
{'pydantic_internal_union_tag_key': 'cat'}},
'dog': {'type': 'definition-ref', 'metadata':
{'pydantic_internal_union_tag_key': 'dog'}}
},
'discriminator': <function get_pet_type at 0x...>
} used with Discriminator
For further information visit
https://errors.pydantic.dev/2.12/u/callable-discriminator-no-tag
Root Cause: This appears to be caused by commit 42b250d (https://github.com
/fastapi/fastapi/commit/42b250d14dd42d3c0c24dd085fa53878172a985f) which
fixed arbitrary_types_allowed=True but introduced a regression in how
discriminated unions are handled.
The change in fastapi/_compat/v2.py now includes *self.field_info.metadata
when creating TypeAdapters, which causes discriminator metadata to be
duplicated/nested when the union is wrapped in Annotated[..., Body(...)].
Workaround: Use pet: Pet = Body(...) instead of pet: Annotated[Pet,
Body(...)]
Operating System
Linux, macOS
Operating System Details
No response
FastAPI Version
0.124.2
Pydantic Version
2.12.5
Python Version
3.12
Additional Context
-
The error shows tags ARE present ('pydantic_internal_union_tag_key':
'cat'), so Pydantic sees them but validation fails- This only affects callable discriminators with Tag(), not field-based
discriminators with Literal - Both patterns (= Body(...) and Annotated[..., Body(...)]) should be
functionally equivalent - This is a breaking change in a patch release
Is this a known issue? Should I file a bug report?
- This only affects callable discriminators with Tag(), not field-based