alter-type-add-value-in-transaction
ALTER TYPE ADD VALUE in the same transaction as a statement referencing the new value will fail.
- operation
- Enums
- lock taken
- no table lock
- remediation
- Manual rewrite
- category
- Types & schema style
- Breaks a rolling deploy
What triggers it
An InsertStmt or UpdateStmt that is preceded, within the same explicit transaction, by at least one AlterEnumStmt. The rule replays statements 0..statementIndex-1, flipping an inTransaction flag on isTransactionBegin / isTransactionEnd (both of which read TransactionStmt.kind from the parse tree, not the leading keyword) and pushing every AlterEnumStmt seen while the flag is set. It fires when the flag is still set and the list is non-empty.
What does not
Any file with no explicit BEGIN. inTransaction starts false and is only ever set by an actual TransactionStmt, so a migration whose runner supplies the transaction — which is most of them — never fires, no matter how the statements are ordered. DELETE and SELECT, since only InsertStmt and UpdateStmt are considered. An INSERT that comes before the ALTER TYPE, or after a COMMIT that clears the list.
Where it applies
Applies to every PostgreSQL version MigrationPilot targets. It works on the SQL text alone — no database connection needed.
The failure mode changes by version. Before PG 12, ALTER TYPE ... ADD VALUE cannot run inside a transaction block at all — MP012 covers that. From PG 12 the statement is allowed in a transaction but the new label is invisible to the rest of it, and the offending INSERT/UPDATE fails with "unsafe use of new value". The rule has no version gate and reports the PG 12+ wording either way.
The lock, and what it blocks
No table lock is the subject. ALTER TYPE ... ADD VALUE takes a lock on the type, not on tables using it, and the rule reports a visibility rule rather than a contention one: within the adding transaction the new label has no committed catalog row that other statements can resolve, so the statement errors instead of blocking.
Why it matters
On PostgreSQL < 12, ALTER TYPE ADD VALUE cannot run inside a transaction at all. On PG 12+, it can run in a transaction but the new enum value is not visible to other statements in the same transaction — any INSERT or UPDATE referencing the new value will fail.
Unsafe, and safe
Flagged
BEGIN; ALTER TYPE status ADD VALUE 'archived'; INSERT INTO events (status) VALUES ('archived'); COMMIT;
Safe alternative
-- Transaction 1: ALTER TYPE status ADD VALUE 'archived'; -- Transaction 2 (after commit): INSERT INTO events (status) VALUES ('archived');
Deploy and transaction boundaries
The fix is a transaction boundary, which usually means a deploy boundary. ALTER TYPE ... ADD VALUE has to commit before anything can read the new label, so the ADD VALUE and its first use belong in two separate migrations, and where to cut is the author decision the fixer refuses to make.
What it assumes
It never checks whether the INSERT or UPDATE actually references the new enum label. Any DML after any ALTER TYPE ... ADD VALUE in the same explicit transaction is flagged, so an unrelated INSERT INTO audit_log in that block is a false positive. Combined with the implicit-transaction blind spot above, this is a rule that misses the common shape and over-reports the uncommon one. The line it records for the tracked ADD VALUE is the statement index plus one, not a file line number, though that value never reaches the message.
What backs this rule
Every rule is a claim about PostgreSQL, so it carries what the claim rests on: a handbook chapter that cites the manual, the incidents that put it there, and the version it was last checked against.
Adding a value to an enum is the smallest schema change there is, and it breaks more migration frameworks than anything else in this handbook — because almost every framework wraps migrations in a transaction by default, and this statement has rules about transactions.
- verified against
- PostgreSQL 17.10
- last checked
- 2026-08-11
- confidence
- High
PostgreSQL manual
Public incidents and write-ups
What the CLI prints
✗ [MP054] CRITICAL (line 3)
INSERT/UPDATE in the same transaction as ALTER TYPE "status" ADD VALUE 'archived'. The new enum value is not visible until COMMIT, so this statement will fail.
Safe alternative:
-- Split into separate transactions:
-- Transaction 1: ALTER TYPE status ADD VALUE 'archived';
-- Transaction 2 (after COMMIT): INSERT INTO events (status) VALUES ('archived')...
Why: On PostgreSQL < 12, ALTER TYPE ADD VALUE cannot run inside a transaction at all. On PG 12+, it can run in a transaction but the new enum value is not visible to other statements in the same transaction. Any INSERT or UPDATE referencing the new value will fail with "unsafe use of new value." Prisma, TypeORM, and Alembic frequently generate migrations that trigger this.
Docs: https://migrationpilot.dev/rules/mp054Generated by running the CLI's own formatter over the flagged example above, so it is the text the tool actually produces. A real run also reports the other rules that fire on the same statement; those blocks are left out here.
Turning it off
For one statement, put a comment on the line before it:
-- migrationpilot-disable MP054 BEGIN;
For the whole project, in .migrationpilotrc.yml — by name or by id:
rules:
MP054: false
# or keep it, and downgrade it
rules:
MP054:
severity: warningTry it
Open this rule's flagged example in the playground. It runs in your browser — edit it and watch the finding appear and disappear.
Run MP054 in the playground