Introduction

Flyway tracks applied migrations in the flyway_schema_history table, storing a checksum of each migration script. When a migration script is modified after being applied (even whitespace changes), Flyway detects the checksum mismatch and refuses to run further migrations with Validate failed: Migrations have failed validation ... Migration checksum mismatch. This is a safety mechanism to prevent silent schema drift, but it blocks deployments when a team member edits an already-applied migration file. The fix requires either repairing the recorded checksum or reverting the migration script to its original state.

Symptoms

bash
org.flywaydb.core.internal.command.DbValidate$1: Validate failed: Migrations have failed validation
Migration checksum mismatch for migration 3
-> Applied to database : 1234567890
-> Resolved locally    : 0987654321

Or:

bash
FlywayException: Validate failed:
Detected resolved migration not applied to database: 4
  -> Migration Description: Add user preferences

Common Causes

  • Migration script edited after deployment: Whitespace, comments, or SQL changes
  • Branch merge conflict: Two branches modify the same migration file
  • Format changes: Reformatting SQL changes checksum even if logic is same
  • Repeatable migration modified unexpectedly: Repeatable migrations should be replaceable
  • Manual database changes: Schema modified outside Flyway, causing drift
  • Migration number reused: New migration given number already used in history

Step-by-Step Fix

Step 1: Repair checksum for already-applied migrations

```bash # Update Flyway's recorded checksum to match current script flyway repair

# Or with Spring Boot mvn spring-boot:run -Dspring-boot.run.arguments="--flyway.repair=true" ```

Step 2: Create new migration to fix schema drift

```sql -- DO NOT edit V3__add_user_table.sql after it's been applied -- Instead, create a NEW migration:

-- V4__fix_user_table_columns.sql ALTER TABLE users ADD COLUMN IF NOT EXISTS email VARCHAR(255); ALTER TABLE users ALTER COLUMN name SET NOT NULL; ```

Step 3: Handle repeatable migrations correctly

```sql -- Repeatable migrations (R__ prefix) are re-applied when changed -- R__create_views.sql CREATE OR REPLACE VIEW user_summary AS SELECT u.id, u.name, COUNT(o.id) as order_count FROM users u LEFT JOIN orders o ON u.id = o.user_id GROUP BY u.id, u.name;

-- This is SAFE to modify -- Flyway will re-run it -- Flyway tracks repeatable migrations separately from versioned ones ```

Prevention

  • Never modify a versioned migration (V#__*.sql) after it has been applied
  • Use flyway repair to update checksums when migration changes are intentional
  • Create new migrations to fix schema issues rather than editing old ones
  • Use repeatable migrations (R__) for views, procedures, and functions that should be replaceable
  • Add Flyway validation to CI/CD pipelines to catch checksum mismatches before deployment
  • Use version control hooks to prevent edits to already-deployed migration files
  • Keep migration scripts immutable -- treat them as append-only records of schema history