{"record":{"id":"93d31554019e08f5","repo":"golang-migrate/migrate","slug":"database-is-dirty","errorCode":null,"errorMessage":"database is dirty","messagePattern":"database is dirty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"database/cassandra/cassandra.go","lineNumber":34,"sourceCode":")\n\nfunc init() {\n\tdb := new(Cassandra)\n\tdatabase.Register(\"cassandra\", db)\n}\n\nvar (\n\tmultiStmtDelimiter = []byte(\";\")\n\n\tDefaultMultiStatementMaxSize = 10 * 1 << 20 // 10 MB\n)\n\nvar DefaultMigrationsTable = \"schema_migrations\"\n\nvar (\n\tErrNilConfig     = errors.New(\"no config\")\n\tErrNoKeyspace    = errors.New(\"no keyspace provided\")\n\tErrDatabaseDirty = errors.New(\"database is dirty\")\n\tErrClosedSession = errors.New(\"session is closed\")\n)\n\ntype Config struct {\n\tMigrationsTable       string\n\tKeyspaceName          string\n\tMultiStatementEnabled bool\n\tMultiStatementMaxSize int\n}\n\ntype Cassandra struct {\n\tsession  *gocql.Session\n\tisLocked atomic.Bool\n\n\t// Open and WithInstance need to guarantee that config is never nil\n\tconfig *Config\n}\n","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/golang-migrate/migrate/blob/01a9643f1475e75bb6d6224ddeaf9d8e2434ca8a/database/cassandra/cassandra.go#L16-L52","documentation":"ErrDatabaseDirty indicates the migrations table contains a row whose 'dirty' flag is true, meaning a previous migration failed partway (applied but not recorded, or recorded but not applied). The Cassandra driver returns this from Open/WithInstance and refuses to run further migrations until the state is manually resolved. It protects the schema from inconsistent concurrent or partial application.","triggerScenarios":"A previous migration run crashed or was killed mid-migration; SetVersion was called with dirty=true and never cleared; two migrate processes raced and one left the version row dirty.","commonSituations":"Deploy pod killed during migration, network drop between applying DDL and updating the version row, developer interrupting a long migration locally.","solutions":["Inspect the schema_migrations table in the keyspace and determine whether the last migration actually applied.","Fix the schema manually (apply or roll back the partial migration), then force the version: migrate.Force(version) with the correct non-dirty version.","Re-run migrations; if the failure keeps recurring, run migrations from a single serialized process (avoid concurrent deployers)."],"exampleFix":"// before (retrying while dirty just fails again)\n// after resolving the state manually:\nm, _ := migrate.New(\"cassandra://host/keyspace\", \"file://migrations\")\nerr := m.Force(3) // set version 3, dirty=false, after repairing schema","handlingStrategy":"try-catch","validationCode":"var version, dirty bool\nerr := session.Query(\"SELECT dirty FROM \" + migrationsTable).Scan(&dirty)\n// if dirty is true, resolve before running migrations","typeGuard":null,"tryCatchPattern":"if err := m.Up(); err != nil {\n    if errors.Is(err, cassandra.ErrDatabaseDirty) {\n        // inspect schema_migrations, repair schema, then:\n        if ferr := m.Force(lastGoodVersion); ferr != nil { return ferr }\n        return m.Up()\n    }\n    return err\n}","preventionTips":["Run migrations from a single serialized runner (no concurrent deployers).","Wrap migrations in a job that is not killed mid-run (graceful shutdown windows).","Alert on ErrDatabaseDirty so the state is repaired promptly.","Keep migrations small so a crash window is minimal."],"tags":["go","database","migration","cassandra","go-migrate"],"backgroundTag":"migration-dirty-state","analyzedSha":"01a9643f1475e75bb6d6224ddeaf9d8e2434ca8a","analyzedAt":"2026-09-02T19:38:29.671Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}