Apariencia
❌ EmailStr rechaza admin@orderflow.local — "special-use or reserved name"
Python para Backend · Clase 7 ·
users_service/scripts/create_admin.py
🩻 Contexto
El script create_admin.py crea el usuario admin insertándolo directo con SQLAlchemy (User(...), sin pasar por el schema UserCreate), con el email por defecto admin@orderflow.local — y eso funciona sin problema, el admin se crea.
Pero al intentar loguearse con ese mismo email (POST /api/v1/auth/login, que sí valida el body con el schema LoginRequest, que usa EmailStr), FastAPI responde 422 con:
json
{
"detail": [{
"type": "value_error",
"loc": ["body", "email"],
"msg": "value is not a valid email address: The part after the @-sign is a
special-use or reserved name that cannot be used with email."
}]
}🔍 Causa
.local es un dominio de uso especial/reservado (RFC 6762 — reservado para resolución de nombres en red local vía mDNS/Bonjour, no para correo real). La librería email-validator (la que usa EmailStr de Pydantic por debajo) mantiene una lista de estos dominios reservados (.local, .test, .example, .invalid, .localhost, ...) y los rechaza por defecto, sin importar que el formato usuario@dominio sea sintácticamente válido.
💡 Por qué el admin SÍ se creó pero SÍ falla el login:
create_admin.pyarma elUser(...)directo (sin pasar porUserCreate/EmailStr), así que Pydantic nunca valida ese email al crearlo.LoginRequest, en cambio, SÍ tieneemail: EmailStr, y ahí es donde salta el error — la inconsistencia está en que un camino valida y el otro no.
⚠️ Es más grave de lo que parece al principio:
EmailStrno solo valida al recibir datos (LoginRequest) — también valida al devolver una respuesta (UserResponse). Mientras ese usuario con.localsiga en la tabla, cualquier endpoint que lo incluya en la respuesta explota con500 Internal Server Error(fastapi.exceptions.ResponseValidationError) — en este proyecto, eso rompióGET /api/v1/users(list_users) para todos los usuarios, no solo para ese uno. La solución real no es solo "no loguearse con ese email" — es no dejar ese dato en la base:DELETE FROM users WHERE email='admin@orderflow.local';(oUPDATEa un dominio válido).
✅ Solución
Usar un dominio que no esté en la lista de reservados al definir ADMIN_EMAIL (variable de entorno que lee el script):
bash
ADMIN_EMAIL=admin@orderflow.dev python3 -m scripts.create_admin
# o cualquier dominio "real" — .dev, .com, .io, etc. — no hace falta que exista de verdad,
# EmailStr valida el FORMATO y que no sea un dominio reservado, no que el dominio responda.⚠️ Ojo,
.com/.orgcon nombres tipoexample.comtambién están reservados (RFC 2606, para documentación) — evitarexample.com,example.org,example.netcomo dominio de prueba también.
📎 Apuntes relacionados
- Clase 7 —
users_service/scripts/create_admin.py - [[2026-08-20-importerror-email-validator]] — mismo mecanismo (
email-validator) fallando por otro motivo (falta el paquete)