plandex-ai/plandex · critical
error running migrations: %v
Error message
error running migrations: %v
What it means
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.
Source
Thrown at app/server/db/db.go:166
// Uncomment below and edit 'stepsBack' to go back a specific number of migrations
// if os.Getenv("GOENV") == "development" {
// stepsBack := 1
// err = m.Steps(-stepsBack)
// if err != nil {
// return fmt.Errorf("error running down migrations: %v", err)
// }
// log.Printf("went down %d migration\n", stepsBack)
// }
err = m.Up()
if err != nil {
if err == migrate.ErrNoChange {
log.Println("migration state is up to date")
} else {
return fmt.Errorf("error running migrations: %v", err)
}
}
if err == nil {
log.Println("ran migrations successfully")
}
return nil
}
View on GitHub (pinned to e2d772072e)
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
Example fix
// before
return fmt.Errorf("error running migrations: %v", err)
// after
var dirty migrate.ErrDirty
if errors.As(err, &dirty) {
log.Printf("dirty migration at %d; forcing", dirty)
if forceErr := m.Force(int(dirty)); forceErr != nil { return forceErr }
return migrationsUp(dir)
}
return fmt.Errorf("error running migrations: %v", err) Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check dirty state before running
var dirty, version bool
if err := Conn.Get(&dirty, "SELECT dirty FROM schema_migrations LIMIT 1"); err == nil && dirty {
return errors.New("schema_migrations is dirty; force version before migrating")
} Try / catch
if err := MigrationsUp(); err != nil {
if strings.Contains(err.Error(), "error running migrations") {
if errors.Is(err, migrate.ErrDirty) || strings.Contains(err.Error(), "Dirty database") {
log.Printf("dirty migration state: %v — manual force needed", err)
}
return err
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- error creating postgres driver: %v
- error creating migration instance: %v
- error scanning repo lock: %v
- refresh failed - decode: %w
- error unmarshalling JSON file: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/2ab0908b771e0c15.
Report an issue: GitHub.