Summary
auto_migrate=True creates Postgres native enum types for StrEnum fields at table-creation time, but never evolves them: adding a member to the Python StrEnum after the type exists in the database is silently ignored by the migration planner. The first query or insert using the new member then fails at the database with invalid input value for enum <type>: "<value>" — an unhandled exception at runtime, invisible to any test that runs against a freshly-created schema (fresh schemas get the complete enum, so the gap is structurally untestable from the app side).
Repro
- Model with
class Provider(StrEnum): PLAID = "plaid" and a field provider: Provider; connect(..., auto_migrate=True) — table + provider enum type created with one label.
- Add
MX = "mx" to the StrEnum. Reconnect with auto_migrate=True against the same database — no DDL is planned.
Model.where(lambda m: m.provider == Provider.MX) → invalid input value for enum provider: "mx".
Real-world hit
pinch-backend M13 (syn54x/pinch-backend#93) added MX = "mx" to ConnectionProvider (created in M7 with only plaid). Every test was green — the suite's throwaway schemas always create the enum complete — and every existing database 500s on the first MX request. Found in a local smoke test; production would have hit it on deploy.
Suggested fix
The auto-migrate diff should compare the StrEnum's members against pg_enum for the existing type and emit ALTER TYPE <name> ADD VALUE IF NOT EXISTS '<value>' for each missing label (append-only; PG12+ allows it inside a transaction with the caveat that the new value is unusable until commit — emitting it outside the main migration transaction, or as its own autocommit statement, sidesteps the older-PG restriction entirely). Removed/renamed labels are a genuinely hard problem and can stay out of scope — additive evolution covers the overwhelmingly common case and is what silently breaks today.
Possibly related context: #199 touches enum ADD COLUMN planner divergence (native enum vs varchar resolution), but this issue is about evolving an existing enum type's value set, not column creation.
Summary
auto_migrate=Truecreates Postgres native enum types forStrEnumfields at table-creation time, but never evolves them: adding a member to the PythonStrEnumafter the type exists in the database is silently ignored by the migration planner. The first query or insert using the new member then fails at the database withinvalid input value for enum <type>: "<value>"— an unhandled exception at runtime, invisible to any test that runs against a freshly-created schema (fresh schemas get the complete enum, so the gap is structurally untestable from the app side).Repro
class Provider(StrEnum): PLAID = "plaid"and a fieldprovider: Provider;connect(..., auto_migrate=True)— table +providerenum type created with one label.MX = "mx"to the StrEnum. Reconnect withauto_migrate=Trueagainst the same database — no DDL is planned.Model.where(lambda m: m.provider == Provider.MX)→invalid input value for enum provider: "mx".Real-world hit
pinch-backend M13 (syn54x/pinch-backend#93) added
MX = "mx"toConnectionProvider(created in M7 with onlyplaid). Every test was green — the suite's throwaway schemas always create the enum complete — and every existing database 500s on the first MX request. Found in a local smoke test; production would have hit it on deploy.Suggested fix
The auto-migrate diff should compare the StrEnum's members against
pg_enumfor the existing type and emitALTER TYPE <name> ADD VALUE IF NOT EXISTS '<value>'for each missing label (append-only; PG12+ allows it inside a transaction with the caveat that the new value is unusable until commit — emitting it outside the main migration transaction, or as its own autocommit statement, sidesteps the older-PG restriction entirely). Removed/renamed labels are a genuinely hard problem and can stay out of scope — additive evolution covers the overwhelmingly common case and is what silently breaks today.Possibly related context: #199 touches enum ADD COLUMN planner divergence (native enum vs varchar resolution), but this issue is about evolving an existing enum type's value set, not column creation.