{"record":{"id":"2ab0908b771e0c15","repo":"plandex-ai/plandex","slug":"error-running-migrations-v","errorCode":null,"errorMessage":"error running migrations: %v","messagePattern":"error running migrations: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"app/server/db/db.go","lineNumber":166,"sourceCode":"\n\t// Uncomment below and edit 'stepsBack' to go back a specific number of migrations\n\t// if os.Getenv(\"GOENV\") == \"development\" {\n\t// \tstepsBack := 1\n\t// \terr = m.Steps(-stepsBack)\n\t// \tif err != nil {\n\t// \t\treturn fmt.Errorf(\"error running down migrations: %v\", err)\n\t// \t}\n\t// \tlog.Printf(\"went down %d migration\\n\", stepsBack)\n\t// }\n\n\terr = m.Up()\n\n\tif err != nil {\n\t\tif err == migrate.ErrNoChange {\n\t\t\tlog.Println(\"migration state is up to date\")\n\t\t} else {\n\n\t\t\treturn fmt.Errorf(\"error running migrations: %v\", err)\n\t\t}\n\t}\n\n\tif err == nil {\n\t\tlog.Println(\"ran migrations successfully\")\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":148,"sourceCodeEnd":176,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/db.go#L148-L176","documentation":"After m.Up() runs, any error other than migrate.ErrNoChange is wrapped as this error. ErrNoChange is treated as success (already up to date), so this fires only for real migration failures: a SQL error in a migration file, a dirty migration state, or lost connection mid-migration.","triggerScenarios":"m.Up() fails because a migration SQL statement errors, the schema_migrations table is dirty from a previous partial migration (ErrDirty), or connectivity is lost during migration execution.","commonSituations":"A previously failed migration left the database at a dirty version; new migration SQL incompatible with existing data; concurrent migration runners (multiple pods starting at once) racing on schema_migrations.","solutions":["Read the wrapped %v error to find the failing migration version and SQL statement","If dirty, use m.Force(version) (the commented dev path in this file) or manually fix schema_migrations, then re-run after correcting the migration","Ensure only one process runs migrations (advisory lock or single migration job)","Roll back the bad migration with its .down.sql, fix, and re-apply"],"exampleFix":"// before\nreturn fmt.Errorf(\"error running migrations: %v\", err)\n// after\nvar dirty migrate.ErrDirty\nif errors.As(err, &dirty) {\n    log.Printf(\"dirty migration at %d; forcing\", dirty)\n    if forceErr := m.Force(int(dirty)); forceErr != nil { return forceErr }\n    return migrationsUp(dir)\n}\nreturn fmt.Errorf(\"error running migrations: %v\", err)","handlingStrategy":"try-catch","validationCode":"// pre-check dirty state before running\nvar dirty, version bool\nif err := Conn.Get(&dirty, \"SELECT dirty FROM schema_migrations LIMIT 1\"); err == nil && dirty {\n    return errors.New(\"schema_migrations is dirty; force version before migrating\")\n}","typeGuard":null,"tryCatchPattern":"if err := MigrationsUp(); err != nil {\n    if strings.Contains(err.Error(), \"error running migrations\") {\n        if errors.Is(err, migrate.ErrDirty) || strings.Contains(err.Error(), \"Dirty database\") {\n            log.Printf(\"dirty migration state: %v — manual force needed\", err)\n        }\n        return err\n    }\n    return err\n}","preventionTips":["Run migrations from a single process (use a postgres advisory lock or a dedicated migration job)","Always pair .up.sql with .down.sql and test them in CI","Never edit already-applied migrations; add new ones instead","Fix failing migration SQL before forcing/re-running, not after"],"tags":["migrations","golang-migrate","database","schema"],"backgroundTag":"migration-run-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}