no-enum-value-removal
DROP TYPE destroys the enum and all columns that use it.
- operation
- Enums
- lock taken
- ACCESS EXCLUSIVE
- remediation
- Manual rewrite
- category
- Data safety
- Can lose data
What triggers it
Fires on any DropStmt whose removeType is OBJECT_TYPE — that is, any DROP TYPE statement.
What does not
Any statement that is not a DropStmt, or a DropStmt targeting something other than OBJECT_TYPE (tables, indexes, views, and so on), returns null immediately.
Where it applies
Applies to every PostgreSQL version MigrationPilot targets. It works on the SQL text alone — no database connection needed.
The lock, and what it blocks
The DROP TYPE statement itself is not characterized by a lock in this check — PostgreSQL simply refuses to drop a type still referenced by a column. ACCESS EXCLUSIVE only enters the picture in the safe alternative, at the ALTER COLUMN ... TYPE step that migrates each table to the recreated type.
Why it matters
PostgreSQL has no ALTER TYPE DROP VALUE. Dropping and recreating an enum type fails if any column references it, and CASCADE drops those columns too.
Unsafe, and safe
Flagged
DROP TYPE status;
Safe alternative
-- Enum values cannot be removed in PostgreSQL. -- Consider using a TEXT column with a CHECK constraint instead.
What it assumes
The check only tests whether removeType equals OBJECT_TYPE — it does not confirm the dropped type is actually an enum, so DROP TYPE on a composite type or domain triggers the same enum-recreation guidance, which does not really apply there.
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
⚠ [MP024] WARNING (line 1)
DROP TYPE "status" will destroy the type and fail if any columns use it. PostgreSQL cannot remove individual enum values. The type must be recreated.
Safe alternative:
-- Safe enum recreation pattern:
-- 1. Create the new type:
-- CREATE TYPE status_new AS ENUM ('value1', 'value2');
-- 2. Migrate columns (ACCESS EXCLUSIVE lock, rewrites table):
-- ALTER TABLE <table> ALTER COLUMN <col>
-- TYPE status_new USING <col>::text::status_new;
-- 3. Drop the old type:
-- DROP TYPE status;
-- 4. Rename:
-- ALTER TYPE status_new RENAME TO status;
Why: Dropping an enum type destroys the type and fails if any columns reference it. PostgreSQL cannot remove individual enum values. You must recreate the type and migrate all columns, which requires an ACCESS EXCLUSIVE lock per table.
Docs: https://migrationpilot.dev/rules/mp024Generated 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 MP024 DROP TYPE status;
For the whole project, in .migrationpilotrc.yml — by name or by id:
rules:
MP024: false
# or keep it, and downgrade it
rules:
MP024:
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 MP024 in the playground