{"record":{"id":"76455d25f981b98c","repo":"golang-migrate/migrate","slug":"database-is-dirty-76455d","errorCode":null,"errorMessage":"database is dirty","messagePattern":"database is dirty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"database/pgx/pgx.go","lineNumber":51,"sourceCode":"\tdb := Postgres{}\n\tdatabase.Register(\"pgx\", &db)\n\tdatabase.Register(\"pgx4\", &db)\n}\n\nvar (\n\tmultiStmtDelimiter = []byte(\";\")\n\n\tDefaultMigrationsTable       = \"schema_migrations\"\n\tDefaultMultiStatementMaxSize = 10 * 1 << 20 // 10 MB\n\tDefaultLockTable             = \"schema_lock\"\n\tDefaultLockStrategy          = LockStrategyAdvisory\n)\n\nvar (\n\tErrNilConfig      = fmt.Errorf(\"no config\")\n\tErrNoDatabaseName = fmt.Errorf(\"no database name\")\n\tErrNoSchema       = fmt.Errorf(\"no schema\")\n\tErrDatabaseDirty  = fmt.Errorf(\"database is dirty\")\n)\n\ntype Config struct {\n\tMigrationsTable       string\n\tDatabaseName          string\n\tSchemaName            string\n\tLockTable             string\n\tLockStrategy          string\n\tmigrationsSchemaName  string\n\tmigrationsTableName   string\n\tStatementTimeout      time.Duration\n\tMigrationsTableQuoted bool\n\tMultiStatementEnabled bool\n\tMultiStatementMaxSize int\n}\n\ntype Postgres struct {\n\t// Locking and unlocking need to use the same connection","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/golang-migrate/migrate/blob/01a9643f1475e75bb6d6224ddeaf9d8e2434ca8a/database/pgx/pgx.go#L33-L69","documentation":"ErrDatabaseDirty is returned when the driver finds the migrations/version table in an inconsistent state — most commonly a recorded version in the migrations table that has no corresponding migration file, or a setDirty record from a previously failed migration. The pgx driver (like mysql, cassandra and others sharing this sentinel name) returns it from SetVersion/EnsureVersion paths, aborting further migrations until an operator intervenes.","triggerScenarios":"Running migrations after a previous migration run failed mid-way (dirty state recorded); the version row references a migration number not present in the source; a manual edit or partial restore of the schema_migrations table.","commonSituations":"A migration DDL was killed/timed out leaving partial changes; deploying new migration files while the DB records a higher version (out-of-order/deleted files); restoring a DB dump without the matching migration sources.","solutions":["Inspect the version table (e.g. SELECT * FROM schema_migrations) and the recorded version vs your migration files","If the failed migration's effects should be kept, manually update the version row to the correct value (e.g. force to the version before the failure: UPDATE schema_migrations SET version=..., dirty=false)","If effects should be rolled back, manually revert the partial changes, then clear the dirty flag and re-run","Ensure migration files are never deleted/renamed after being applied across environments"],"exampleFix":"// before\npsql -c \"SELECT version, dirty FROM schema_migrations;\" -- shows dirty=true\n// after\npsql -c \"UPDATE schema_migrations SET dirty = false WHERE version = 12;\" -- after manually verifying/rolling back migration 12's changes","handlingStrategy":"try-catch","validationCode":"// before migrating, check for dirty state\nvar version int\nvar dirty bool\nerr := db.QueryRow(\"SELECT version, dirty FROM schema_migrations\").Scan(&version, &dirty)\nif err == nil && dirty {\n    return fmt.Errorf(\"database is dirty at version %d; resolve manually before migrating\", version)\n}","typeGuard":null,"tryCatchPattern":"if err := m.Up(); err != nil {\n    var dbErr *database.Error\n    if errors.As(err, &dbErr) && strings.Contains(err.Error(), \" Dirty database version\") {\n        return fmt.Errorf(\"migration aborted, DB left dirty at recorded version; inspect schema_migrations and resolve manually: %w\", err)\n    }\n    return err\n}","preventionTips":["Always run migrations inside transactions/with a migration tool so failures are recorded consistently","Never delete or rename applied migration files","Alert on failed migration runs — dirty state requires manual resolution, retries will keep failing","Keep schema_migrations backed up/restorable consistently with the DB state"],"tags":["postgres","pgx","migrations","database-state","dirty-database"],"backgroundTag":"dirty-database-state","analyzedSha":"01a9643f1475e75bb6d6224ddeaf9d8e2434ca8a","analyzedAt":"2026-09-02T19:38:29.671Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}