Rule index
Every code mrt check can print: 54 rules across 8 groups. Extracted from the detector sources, so this page cannot drift from the implementation — tests/test_rule_index.py fails if it does.
Suppress any single rule inline with # noqa: MRTxxx, or change its severity with MRTConfig(severity_overrides={...}). See the pattern explanations for what each one costs you in production.
A rule listed as error / warning fires at either severity depending on how certain the detection is — MRT411, for instance, is an error when a field is explicitly null=False with no default and a warning when that has to be inferred from the field type.
MRT1xx — Irreversible migrations
| Code |
Severity |
Pattern |
Migrations |
Details |
MRT101 |
error |
Missing downgrade |
Alembic |
explained |
MRT102 |
error |
No-op downgrade |
Alembic |
explained |
MRT103 |
warning |
Data transform without reverse |
Alembic |
— |
MRT104 |
warning |
Raw SQL (op.execute) |
Alembic |
explained |
MRT105 |
warning |
context.execute without reverse |
Alembic |
— |
MRT106 |
warning |
bulk_insert without reverse |
Alembic |
— |
MRT107 |
error |
RunPython without reverse_code |
Django |
— |
MRT108 |
error |
RunSQL without reverse_sql |
Django |
— |
MRT2xx — Data loss
| Code |
Severity |
Pattern |
Migrations |
Details |
MRT201 |
error |
DROP COLUMN in upgrade |
Alembic |
explained |
MRT202 |
error |
DROP TABLE in upgrade |
Alembic |
explained |
MRT203 |
error |
TRUNCATE |
Alembic |
explained |
MRT204 |
warning |
CASCADE DELETE |
Alembic |
explained |
MRT205 |
error |
DROP FOREIGN KEY without restore |
Alembic |
— |
MRT206 |
error |
DROP COLUMN in batch_alter_table |
Alembic |
explained |
MRT207 |
error |
DROP VIEW without reverse |
Alembic |
explained |
MRT208 |
error |
Multi-step destructive migration |
Alembic |
explained |
MRT209 |
error |
RemoveField |
Django |
— |
MRT210 |
error |
DeleteModel |
Django |
— |
MRT211 |
error |
RunSQL DROP TABLE |
Django |
— |
MRT212 |
error |
RunSQL TRUNCATE |
Django |
— |
MRT213 |
warning |
SET NOT NULL on existing column |
Alembic |
— |
MRT3xx — Renames and type changes
| Code |
Severity |
Pattern |
Migrations |
Details |
MRT301 |
error |
rename_table without reverse |
Alembic |
explained |
MRT302 |
error |
rename_column without reverse |
Alembic |
explained |
MRT303 |
warning |
Column type change |
Alembic |
explained |
MRT304 |
error |
ENUM value added |
Alembic |
explained |
MRT305 |
warning |
RenameModel with data-loss operations |
Django |
— |
MRT4xx — Constraints, nullability and locking
| Code |
Severity |
Pattern |
Migrations |
Details |
MRT401 |
warning |
NOT NULL without default |
Alembic |
explained |
MRT402 |
warning |
NOT NULL without reverting nullable |
Alembic |
explained |
MRT403 |
warning |
NOT NULL via raw SQL without reverse |
Alembic |
explained |
MRT404 |
warning |
ADD COLUMN with volatile DEFAULT |
Alembic |
explained |
MRT405 |
warning |
ADD COLUMN with server_default |
Alembic |
explained |
MRT406 |
warning |
UNIQUE constraint on existing data |
Alembic |
explained |
MRT407 |
warning |
INDEX without CONCURRENTLY |
Alembic |
explained |
MRT408 |
warning |
DROP INDEX without reverse |
Alembic |
explained |
MRT409 |
warning |
DROP CONSTRAINT without reverse |
Alembic |
explained |
MRT410 |
warning |
DROP CONSTRAINT in batch_alter_table |
Alembic |
explained |
MRT411 |
error / warning |
AddField NOT NULL without default |
Django |
— |
MRT412 |
error |
AlterField to NOT NULL without default |
Django |
— |
MRT413 |
warning |
AddIndex without atomic=False |
Django |
— |
MRT414 |
warning |
Missing atomic=False |
Django |
— |
MRT415 |
error |
PRAGMA foreign_keys after DML |
Alembic |
— |
MRT5xx — Sequences, triggers and types
| Code |
Severity |
Pattern |
Migrations |
Details |
MRT501 |
warning |
SEQUENCE modification |
Alembic |
explained |
MRT502 |
error |
CREATE TRIGGER without DROP TRIGGER |
Alembic |
— |
MRT503 |
error |
CREATE TYPE without DROP TYPE |
Alembic |
— |
MRT504 |
error |
DROP TRIGGER without recreate |
Alembic |
— |
MRT6xx — Squashed migrations (Django)
| Code |
Severity |
Pattern |
Migrations |
Details |
MRT601 |
error |
Squashed migration: RunPython without reverse_code |
Django |
explained |
MRT602 |
warning |
Squashed migration: missing replaces list |
Django |
explained |
MRT7xx — Rolling-deploy compatibility
| Code |
Severity |
Pattern |
Migrations |
Details |
MRT701 |
error |
DROP COLUMN during rolling deploy |
Alembic, Django |
explained |
MRT702 |
error |
RENAME COLUMN during rolling deploy |
Alembic, Django |
explained |
MRT703 |
error |
DROP TABLE during rolling deploy |
Alembic, Django |
explained |
MRT704 |
error |
ADD NOT NULL column without server_default |
Alembic, Django |
explained |
MRT705 |
warning |
Column type change during rolling deploy |
Alembic |
explained |
MRT9xx — Migration graph
| Code |
Severity |
Pattern |
Migrations |
Details |
MRT901 |
error |
Multiple heads |
Alembic |
explained |
MRT902 |
error |
Syntax error |
Alembic, Django |
— |
Counts
- With a prose section in pattern explanations: 33 of 54. The rest are described by the message
mrt check prints; the Django rules are the largest gap and are not yet written up there.
- Alembic migrations: 41 rules
- Django migrations: 18 rules
- Total distinct codes: 54
A rule listed for both formats is implemented once per format, over that format's own syntax — the two detectors share no rule bodies.