warn-dependent-objects
DROP COLUMN, RENAME COLUMN, or ALTER COLUMN TYPE may silently break views, functions, and triggers that reference the column.
- operation
- Columns
- lock taken
- no table lock
- remediation
- Informational
- category
- Data safety
- Breaks a rolling deploy
What triggers it
Either of two node shapes. A RenameStmt whose renameType is "OBJECT_COLUMN" — the parser emits the enum name, not its ordinal — which is how ALTER TABLE ... RENAME COLUMN arrives; it is checked before anything else, because a column rename is never an AlterTableStmt. Or an AlterTableStmt with a command of subtype AT_DropColumn or AT_AlterColumnType; that loop returns on the first such command. The three produce differently worded messages, and the drop case ships a pg_depend query in safeAlternative that names the specific table and column.
What does not
Renaming anything that is not a column: ALTER TABLE ... RENAME TO is OBJECT_TABLE and belongs to MP028, a constraint rename is OBJECT_TABCONSTRAINT, and an index rename is OBJECT_INDEX. ADD COLUMN, SET NOT NULL, and every other AlterTableCmd subtype are outside the rule. Renaming a column of a view or a materialized view is OBJECT_COLUMN too, and is flagged — dependents break there in exactly the same way.
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
Not a lock rule. DROP COLUMN takes a brief ACCESS EXCLUSIVE for a catalog-only change and ALTER COLUMN ... TYPE holds ACCESS EXCLUSIVE through a full rewrite, but MP017 and MP007 own those stories. This rule is about failures that happen after the migration succeeds: a view, function, or trigger body that still references the column errors at query time, on the next request, not during deployment.
Why it matters
Views, functions, and triggers that reference a column will fail at query time — not at migration time — when the column is dropped, renamed, or its type is changed. PostgreSQL does not automatically update these dependent objects.
Unsafe, and safe
Flagged
ALTER TABLE users DROP COLUMN email; -- Any view that SELECTs email will now fail at query time ALTER TABLE users RENAME COLUMN phone TO phone_number; -- Same for the rename: the view still names phone, and still parses
Safe alternative
-- Check dependencies first: SELECT dependent_ns.nspname || '.' || dependent_view.relname FROM pg_depend JOIN pg_rewrite ON pg_depend.objid = pg_rewrite.oid JOIN pg_class AS dependent_view ON pg_rewrite.ev_class = dependent_view.oid JOIN pg_namespace AS dependent_ns ON dependent_view.relnamespace = dependent_ns.oid JOIN pg_class AS source_table ON pg_depend.refobjid = source_table.oid JOIN pg_attribute ON pg_depend.refobjid = pg_attribute.attrelid AND pg_depend.refobjsubid = pg_attribute.attnum WHERE source_table.relname = 'users' AND pg_attribute.attname = 'email'; -- Then drop only after confirming no dependents
What it assumes
It cannot enumerate dependents. Without a catalog connection there is no way to know whether any view or function references the column, so the rule fires unconditionally on every drop, rename and type change — including on a column nothing has ever referenced. Nothing in the code reads ctx.cluster or ctx.production, so --database-url does not upgrade it to a real dependency check; the pg_depend query it emits is something the operator runs by hand. Its output is a prompt to go look, which is why remediation is informational rather than a rewrite. The rename path was dead until recently — gated behind an AlterTableStmt check a RenameStmt can never satisfy — so a migration linted by an older release was only ever checked for drops and type changes.
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.
ALTER TABLE ... DROP COLUMN is fast.
- verified against
- PostgreSQL 17.10
- last checked
- 2026-08-11
- confidence
- High
Public incidents and write-ups
What the CLI prints
⚠ [MP052] WARNING (line 1)
Dropping column "email" from "users" may break views, functions, or triggers that reference it. Check dependencies before deploying.
Safe alternative:
-- Check for dependent objects before dropping:
SELECT dependent_ns.nspname || '.' || dependent_view.relname AS dependent_object,
dependent_view.relkind
FROM pg_depend
JOIN pg_rewrite ON pg_depend.objid = pg_rewrite.oid
JOIN pg_class AS dependent_view ON pg_rewrite.ev_class = dependent_view.oid
JOIN pg_namespace AS dependent_ns ON dependent_view.relnamespace = dependent_ns.oid
JOIN pg_class AS source_table ON pg_depend.refobjid = source_table.oid
JOIN pg_attribute ON pg_depend.refobjid = pg_attribute.attrelid AND pg_depend.refobjsubid = pg_attribute.attnum
WHERE source_table.relname = 'users' AND pg_attribute.attname = 'email';
Why: Views, functions, and triggers that reference a column will fail at query time, not at migration time, when the column is dropped, renamed, or its type is changed. PostgreSQL does not automatically update these dependent objects. This is the most common cause of post-deployment failures that static analysis cannot fully resolve without a database connection.
Docs: https://migrationpilot.dev/rules/mp052Generated 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 MP052 ALTER TABLE users DROP COLUMN email;
For the whole project, in .migrationpilotrc.yml — by name or by id:
rules:
MP052: false
# or keep it, and downgrade it
rules:
MP052:
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 MP052 in the playground