Prisma enum drift — runtime ALTER TYPE bez updatu schema.prisma
import { Aside } from ‘@astrojs/starlight/components’;
Symptom
Sekce “Symptom”Endpoint nebo stránka náhodně padá pro některé uživatele:
- API vrací HTTP 500
- UI ukazuje generický toast typu „Nepodařilo se načíst data”
- v logu se opakovaně objevuje
PrismaClientUnknownRequestError: Value 'X' not found in enum 'Y' - bug se „opraví” a po několika dnech / po dalším deployi je zpět — typicky po
prisma generatev rámci čistého buildu
Root cause
Sekce “Root cause”Někde v aplikaci (často self-healing cron / lifecycle worker) běží idempotentní raw SQL:
ALTER TYPE "MyEnum" ADD VALUE IF NOT EXISTS 'NEW_STATE';A vzápětí se do sloupce zapíše 'NEW_STATE'. PostgreSQL je v pohodě.
Jenže schema.prisma o té hodnotě neví:
enum MyEnum { OLD_STATE_A OLD_STATE_B // NEW_STATE chybí}Vygenerovaný Prisma client tedy zná jen OLD_STATE_A | OLD_STATE_B. Při čtení řádku, kde už je 'NEW_STATE', runtime neumí enum deserializovat a hodí:
PrismaClientUnknownRequestError:Invalid `prisma.myTable.findUnique()` invocation:Value 'NEW_STATE' not found in enum 'MyEnum'Endpoint to zachytí jako 500, frontend zobrazí generickou hlášku. Každý prisma generate (typicky v rámci pnpm build nebo CI) tu chybu znovu „obnoví” ze zastaralého schématu — což vysvětluje, proč to vypadá jako „opravoval jsem to už několikrát”.
Fix
Sekce “Fix”Dorovnat schema.prisma k tomu, co je už v DB, a vygenerovat klient. DB samotnou není potřeba migrovat (hodnota tam je).
Před:
enum MyEnum { OLD_STATE_A OLD_STATE_B}Po:
enum MyEnum { OLD_STATE_A NEW_STATE OLD_STATE_B}pnpm prisma generate # nebo db:generate v monorepu# čistý build, restart procesuFunguje to proto, že prisma generate produkuje TypeScript definice + runtime mapování enumu z hodnot v schema.prisma. Jakmile tam hodnota je, deserializace projde.
Jak se tomu vyvarovat v jiných systémech
Sekce “Jak se tomu vyvarovat v jiných systémech”- Detection: v rámci
grep -rn 'ALTER TYPE.*ADD VALUE' src/najít všechny runtime mutace enumů a křížově ověřit sschema.prisma. V CI dá smysl skript, který načtepg_enumz testovací DB a srovná s vygenerovaným klientem. - Anti-pattern: „dočasně” přidat hodnotu ALTER TYPE-em jen v cron handleru s tím, že schema.prisma se „dotáhne později”. Nikdy se nedotáhne a každý regenerate to maskuje, dokud někomu v produkci nezačnou padat readlines.
- Lepší přístup: Enum hodnoty patří do migration /
schema.prismajako každá jiná schema změna. Runtime ALTER mít maximálně jako idempotentní bootstrap pro dev/preview prostředí, kde uživatel nemusí pamatovat naprisma migrate. Produkce by měla mít hodnotu už v migrations.
Sister bugs / související
Sekce “Sister bugs / související”- Stejný princip: column drift, kde aplikace přidá sloupec
ALTER TABLE ... ADD COLUMN IF NOT EXISTS, ale Prisma o něm neví — zde to nepadá tak hlasitě (column zmizí zSELECT *výsledků), takže bug může roky tichounce ujídat data. - NextAuth JWT a session: pokud má enum v sobě roli a JWT cachuje starou hodnotu, po přidání nové role uživatelé s tou rolí najednou nemůžou nic, dokud se JWT neobnoví.