Build Errors
Ruff TC003 unsafe-fix breaks Pydantic models using uuid with PEP 563
Ruff TC003 Breaks Pydantic Models Using uuid with PEP 563
Severity: P2 (auto-fix corrupts working Pydantic models silently) · Applies to: any package using
from __future__ import annotations+ Pydantic +uuid.UUIDfields withruff check --unsafe-fixesRelated: ADR-012 — Dev tooling (Biome, git-cliff, tiered hooks, ruff TD rules)
Problem
After running ruff check --unsafe-fixes --fix, Pydantic models that use
uuid.UUID fields fail at runtime with:
pydantic.errors.PydanticUserError: `ModelName` is not fully defined;you should define `uuid`, then call `ModelName.model_rebuild()`.Symptoms:
- Tests that instantiate Pydantic models fail after ruff auto-fix
- Only affects files with
from __future__ import annotations(PEP 563) - Only affects files where
uuidis used in PydanticBaseModelfields
Root Cause
Ruff rule TC003 (“Move standard library import into a type-checking block”)
moves import uuid into an if TYPE_CHECKING: block. This is normally safe
for pure type hints, but breaks Pydantic models when PEP 563 is active.
The interaction:
from __future__ import annotationsmakes all annotations strings (PEP 563)- Pydantic evaluates annotation strings at model creation time to build validators
- When
uuidis behindTYPE_CHECKING, it’s not available at runtime - Pydantic can’t resolve
uuid.UUIDand raisesclass-not-fully-defined
# BREAKS — uuid not available at runtime for Pydanticfrom __future__ import annotationsfrom typing import TYPE_CHECKINGfrom pydantic import BaseModel
if TYPE_CHECKING: import uuid
class MyModel(BaseModel): id: uuid.UUID # Pydantic can't resolve this at runtimeSolution
- Keep
import uuidas a runtime import (not behindTYPE_CHECKING) - Add
TC003to ruff’s ignore list inpyproject.toml:
[tool.ruff.lint]ignore = [ "TC001", # FastAPI needs Pydantic models at runtime, not behind TYPE_CHECKING "TC003", # stdlib uuid used in Pydantic models — must stay at runtime with PEP 563]Correct Pattern
from __future__ import annotations
import uuid # Runtime import — Pydantic needs thisfrom pydantic import BaseModel
class MyModel(BaseModel): id: uuid.UUID # Works: uuid is available at runtimePrevention
Best Practices
- Never run
ruff --unsafe-fixeswithout running tests afterward — unsafe fixes can change runtime behavior - Keep TC003 in the ruff ignore list — this project uses PEP 563 + Pydantic throughout, making TC003 broadly unsafe
- TC001 is already ignored for the same reason — Pydantic models, FastAPI dependencies, and other runtime-evaluated annotations require their imports at runtime
Warning Signs
- Ruff reports TC003 violations on files containing Pydantic models
--unsafe-fixesflag is used without subsequent test verification- New domain entity files that use
from __future__ import annotations
References
- Pydantic docs: postponed annotations
- PEP 563: Postponed Evaluation of Annotations
- Commit that added TC003 ignore: this session (2026-03-21)