All posts

Fix Migration Error in Go

Resolve database migration errors in Go projects using golang-migrate, goose, and Atlas, covering dirty state and version conflicts.

Go Database Migration Errors

Go projects typically use golang-migrate, goose, or atlas for migrations. Each has its own failure modes.

golang-migrate: Dirty Database

The most common error is a "dirty" database state after a failed migration:

error: Dirty database version 3. Fix and force version.

This means migration 3 partially ran and failed. Fix the issue, then:

# Force the version back to the last successful migration
migrate -path ./migrations -database "$DB_URL" force 2

# Then retry
migrate -path ./migrations -database "$DB_URL" up

goose: Version Mismatch

# Check current version
goose -dir ./migrations postgres "$DB_URL" status

# If versions are out of order
goose -dir ./migrations postgres "$DB_URL" fix

Writing Idempotent Migrations

-- migrations/003_add_email_column.up.sql
-- Use IF NOT EXISTS to make it safe to rerun
ALTER TABLE users ADD COLUMN IF NOT EXISTS email VARCHAR(255);
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);

Go Code Integration

import "github.com/golang-migrate/migrate/v4"

func runMigrations(dbURL string) error {
    m, err := migrate.New("file://migrations", dbURL)
    if err != nil {
        return fmt.Errorf("creating migrator: %w", err)
    }
    defer m.Close()

    if err := m.Up(); err != nil && err != migrate.ErrNoChange {
        return fmt.Errorf("running migrations: %w", err)
    }
    return nil
}

Rollback Strategy

Always write both up and down migrations:

migrate create -ext sql -dir migrations -seq add_users_table

Bugsly captures migration failures at application startup, alerting your team before users encounter database-related errors.

Try Bugsly Free

AI-powered error tracking that explains your bugs. Set up in 2 minutes, free forever for small projects.

Get Started Free