golang-migrate/migrate · critical
database is dirty
Error message
database is dirty
What it means
ErrDatabaseDirty signals the migrations table records a migration version with a dirty flag set, meaning a previous migration failed mid-execution (partially applied) and the schema state is unknown. The driver refuses further migrations until a human resolves the state.
Source
Thrown at database/sqlserver/sqlserver.go:31
"github.com/Azure/go-autorest/autorest/adal"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database"
mssql "github.com/microsoft/go-mssqldb" // mssql support
)
func init() {
database.Register("sqlserver", &SQLServer{})
}
// DefaultMigrationsTable is the name of the migrations table in the database
var DefaultMigrationsTable = "schema_migrations"
var (
ErrNilConfig = fmt.Errorf("no config")
ErrNoDatabaseName = fmt.Errorf("no database name")
ErrNoSchema = fmt.Errorf("no schema")
ErrDatabaseDirty = fmt.Errorf("database is dirty")
ErrMultipleAuthOptionsPassed = fmt.Errorf("both password and useMsi=true were passed")
)
var lockErrorMap = map[int]string{
-1: "The lock request timed out.",
-2: "The lock request was canceled.",
-3: "The lock request was chosen as a deadlock victim.",
-999: "Parameter validation or other call error.",
}
// Config for database
type Config struct {
MigrationsTable string
DatabaseName string
SchemaName string
}
// SQL Server connectionView on GitHub (pinned to 01a9643f14)
Solutions
- Inspect the schema_migrations table: check the version and dirty flag, and verify whether the failing migration's DDL actually applied
- Manually fix the schema (complete or roll back the partial migration), then set dirty=false (or force the version)
- Use migrate.Force(version) via CLI or driver to clear the dirty state once the database matches the recorded version, then re-run migrations
- Prevent recurrence by running migrations in a transaction-backed driver or with a lock/single runner
Example fix
-- before (dirty state) SELECT * FROM schema_migrations; -- version 7, dirty 1 -- after verifying migration 7 fully applied UPDATE schema_migrations SET dirty = 0 WHERE version = 7;
Defensive patterns
Strategy: validation
Validate before calling
var version uint; var dirty bool
row := db.QueryRow("SELECT version, dirty FROM schema_migrations")
if err := row.Scan(&version, &dirty); err == nil && dirty {
return fmt.Errorf("database dirty at version %d; resolve manually before migrating", version)
} Try / catch
if errors.Is(err, sqlserver.ErrDatabaseDirty) {
// inspect schema_migrations, fix schema state, then:
// migrate.Force(knownGoodVersion) before retrying Up
} Prevention
- Run migrations under the driver's Lock so only one process migrates at a time
- Use transactional migration runs where the driver supports it
- Alert on dirty=true rows in schema_migrations
- Never force-clear dirty without verifying the actual schema state
When it happens
Trigger: A prior migration panicked, the process crashed, or the connection dropped while a migration was applying, leaving dirty=true on the version row; retrying migrate.Up/Stef afterwards.
Common situations: Long DDL migrations interrupted by deploys or OOM kills; network partitions during migration; concurrent migration processes after a failed run.
Related errors
AI-assisted analysis of golang-migrate/migrate@01a9643f14 (2026-09-02).
Data as JSON: /api/errors/8bf2360ed3311c78.
Report an issue: GitHub.