This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: fastapi-pydantic-v2-discriminated-unions

FastAPI Pydantic V2 Explicit Discriminated Union & Serialization Invariants

Enforces explicit discriminator fields on polymorphic Pydantic v2 unions in high-throughput FastAPI endpoints. Prevents catastrophic O(N) sequential fallback evaluation, accidental data coercion, and event-loop-blocking CPU stalls during deserialization and serialization.

Prohibited Anti-Pattern: Non-Discriminated Polymorphic Unions with Sequential Type Coercion Fallbacks

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: FastAPI Pydantic V2 Explicit Discriminated Union & Serialization Invariants - Enforces explicit discriminator fields on polymorphic Pydantic v2 unions in high-throughput FastAPI endpoints. Prevents catastrophic O(N) sequential fallback evaluation, accidental data coercion, and event-loop-blocking CPU stalls during deserialization and serialization.
globs: app/**/*.py, src/**/*.py, routers/**/*.py, schemas/**/*.py, models/**/*.py
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/fastapi-pydantic-v2-discriminated-unions"
---

# FastAPI Pydantic V2 Explicit Discriminated Union & Serialization Invariants

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Non-Discriminated Polymorphic Unions with Sequential Type Coercion Fallbacks

## System Constraints
You are a Principal Backend Architect enforcing strict Pydantic V2 polymorphic serialization and deserialization standards in FastAPI. You must eliminate untagged union matching, sequential coercion bugs, and redundant serialization overhead that starve the Python async event loop.

## Strict Guidelines
- Engineers MUST ALWAYS annotate polymorphic unions using `Annotated[Union[VariantA, VariantB], Field(discriminator='type_field')]` or `Discriminator` in Pydantic v2.
- Engineers MUST NOT declare bare `Union[ModelA, ModelB, ...]` in request bodies, response models, or nested schema definitions.
- Child polymorphic models MUST declare the discriminator attribute as a constant `Literal['tag_value']` rather than a generic `str`.
- Services processing high-volume polymorphic collections MUST bypass redundant FastAPI response serialization passes by returning pre-dumped `Response(content=adapter.dump_json(instances), media_type='application/json')` or using a module-level `TypeAdapter`.
- Components NEVER execute raw parsing of high-cardinality polymorphic JSON batches directly within async route handlers; compute-bound validation MUST be delegated to worker threads via `asyncio.to_thread` if processing batch payloads.

## Bad vs Good Implementations
### Polymorphic Event Processing with Discriminated Unions

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Bare Union lacks a discriminator key. Pydantic tests variants sequentially in definition order. If a PurchaseEvent arrives, it matches ClickEvent because all ClickEvent fields are present, stripping `amount_cents` and silently corrupting data while consuming O(N) CPU parsing cycles.
```python
from typing import Union
from pydantic import BaseModel
from fastapi import FastAPI

class ClickEvent(BaseModel):
    event_type: str
    target_id: str

class PurchaseEvent(BaseModel):
    event_type: str
    target_id: str
    amount_cents: int

# ANTI-PATTERN: Bare Union forces Pydantic to iterate sequentially through variants.
# It attempts to coerce payloads into ClickEvent first, silently dropping PurchaseEvent fields
# or scaling to O(N * M) validation checks under high throughput.
AnyEvent = Union[ClickEvent, PurchaseEvent]

app = FastAPI()

@app.post("/events")
async def ingest_event(event: AnyEvent) -> AnyEvent:
    return event
```

#### Production Standard (Correct)
> **Standard**: Using `Annotated` with `Field(discriminator='event_type')` and `Literal` values on child models guarantees O(1) lookup against the tag. Invalid or mismatched schemas fail immediately without trial-and-error coercion, eliminating parser stalls and field stripping.
```python
from typing import Annotated, Literal, Union
from pydantic import BaseModel, Field, TypeAdapter
from fastapi import FastAPI, Response

class BaseEvent(BaseModel):
    target_id: str

class ClickEvent(BaseEvent):
    event_type: Literal["click"]

class PurchaseEvent(BaseEvent):
    event_type: Literal["purchase"]
    amount_cents: int

# PRODUCTION INVARIANT: Explicit discriminator ensures O(1) hash lookup matching.
AnyEvent = Annotated[
    Union[ClickEvent, PurchaseEvent],
    Field(discriminator="event_type")
]

event_adapter = TypeAdapter(AnyEvent)
app = FastAPI()

@app.post("/events")
async def ingest_event(event: AnyEvent) -> Response:
    # Zero-coercion, O(1) variant resolution, bypassing redundant response_model re-validation
    serialized = event_adapter.dump_json(event)
    return Response(content=serialized, media_type="application/json")
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: FastAPI Pydantic V2 Explicit Discriminated Union & Serialization Invariants

FastAPI Pydantic V2 Explicit Discriminated Union & Serialization Invariants defines an industrial-grade behavioral standard for backend engineering. Enforces explicit discriminator fields on polymorphic Pydantic v2 unions in high-throughput FastAPI endpoints. Prevents catastrophic O(N) sequential fallback evaluation, accidental data coercion, and event-loop-blocking CPU stalls during deserialization and serialization. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Non-Discriminated Polymorphic Unions with Sequential Type Coercion Fallbacks Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftNon-Discriminated Polymorphic Unions with Sequential Type Coercion FallbacksCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS annotate polymorphic unions using `Annotated[Union[VariantA, VariantB], Field(discriminator='type_field')]` or `Discriminator` in Pydantic v2.

Engineers MUST ALWAYS annotate polymorphic unions using `Annotated[Union[VariantA, VariantB], Field(discriminator='type_field')]` or `Discriminator` in Pydantic v2.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT declare bare `Union[ModelA, ModelB, ...]` in request bodies, response models, or nested schema definitions.

Engineers MUST NOT declare bare `Union[ModelA, ModelB, ...]` in request bodies, response models, or nested schema definitions.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Child polymorphic models MUST declare the discriminator attribute as a constant `Literal['tag_value']` rather than a generic `str`.

Child polymorphic models MUST declare the discriminator attribute as a constant `Literal['tag_value']` rather than a generic `str`.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Services processing high-volume polymorphic collections MUST bypass redundant FastAPI response serialization passes by returning pre-dumped `Response(content=adapter.dump_json(instances), media_type='application/json')` or using a module-level `TypeAdapter`.

Services processing high-volume polymorphic collections MUST bypass redundant FastAPI response serialization passes by returning pre-dumped `Response(content=adapter.dump_json(instances), media_type='application/json')` or using a module-level `TypeAdapter`.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Components NEVER execute raw parsing of high-cardinality polymorphic JSON batches directly within async route handlers

Components NEVER execute raw parsing of high-cardinality polymorphic JSON batches directly within async route handlers; compute-bound validation MUST be delegated to worker threads via `asyncio.to_thread` if processing batch payloads.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is FastAPI Pydantic V2 Explicit Discriminated Union & Serialization Invariants critical for AI coding assistants?

Enforces explicit discriminator fields on polymorphic Pydantic v2 unions in high-throughput FastAPI endpoints. Prevents catastrophic O(N) sequential fallback evaluation, accidental data coercion, and event-loop-blocking CPU stalls during deserialization and serialization. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Non-Discriminated Polymorphic Unions with Sequential Type Coercion Fallbacks) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

1 Rule in Stack

FastAPI