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

  1. Read the wrapped %v error to find the failing migration version and SQL statement
  2. 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
  3. Ensure only one process runs migrations (advisory lock or single migration job)
  4. 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

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


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/2ab0908b771e0c15. Report an issue: GitHub.