no-enum-add-value-in-transaction
ALTER TYPE ... ADD VALUE cannot run inside a transaction block.
- operation
- Enums
- lock taken
- ACCESS EXCLUSIVE
- remediation
- Fixed by --fix
- category
- Types & schema style
- Blocks reads
- Blocks writes
What triggers it
Fires on any AlterEnumStmt (ALTER TYPE ... ADD VALUE ...) found inside a transaction block, as determined by walking backward for an enclosing BEGIN.
What does not
An AlterEnumStmt running outside any transaction block (in autocommit) never fires, on any PostgreSQL version — the rule only cares whether the statement sits inside BEGIN...COMMIT. Non-AlterEnumStmt statements are skipped too.
Where it applies
Applies to every PostgreSQL version MigrationPilot targets. It works on the SQL text alone — no database connection needed.
Behavior genuinely differs by version: before PG 12, ADD VALUE inside a transaction raises a runtime error and fails the migration outright; from PG 12 on it is allowed but still takes ACCESS EXCLUSIVE on the type for the statement.
The lock, and what it blocks
On PG 12+, where this can actually run inside a transaction, PostgreSQL takes ACCESS EXCLUSIVE on the enum type for the duration — short, but enough to block concurrent queries referencing the type. On PG < 12 the statement never gets that far: it raises a runtime error and aborts the transaction instead.
Why it matters
PostgreSQL does not allow adding enum values inside a transaction. If your migration framework wraps statements in BEGIN/COMMIT, this will fail at runtime.
Unsafe, and safe
Flagged
BEGIN; ALTER TYPE status ADD VALUE 'archived'; COMMIT;
Safe alternative
-- Must run outside a transaction ALTER TYPE status ADD VALUE 'archived';
Deploy and transaction boundaries
The auto-fix only lifts the statement out of its BEGIN/COMMIT block when it is the first, last, or only statement in it — if other statements in that block must stay transactional, the migration needs restructuring into more than one step.
What it assumes
The rule trusts ctx.pgVersion to reflect the target database's real major version; if that's misconfigured, a migration flagged as an instant PG-12+ lock concern could actually be one that hard-fails at deploy time on an older server, or the reverse.
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
⚠ [MP012] WARNING (line 2) ALTER TYPE "status" ADD VALUE 'archived' in a transaction. On PG 12+ this works but takes ACCESS EXCLUSIVE on the enum type. Consider running outside the transaction to minimize lock duration. Why: On PostgreSQL versions before 12, ALTER TYPE ADD VALUE inside a transaction raises a runtime error, failing your migration entirely. On PG 12+ it works but takes an ACCESS EXCLUSIVE lock on the type, which can block concurrent queries. Docs: https://migrationpilot.dev/rules/mp012
Generated 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 MP012 BEGIN;
For the whole project, in .migrationpilotrc.yml — by name or by id:
rules:
MP012: false
# or keep it, and downgrade it
rules:
MP012:
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 MP012 in the playground