Introduction
Flyway calculates a checksum for each migration file and stores it in the flyway_schema_history table. When a migration file is modified after being applied (even a whitespace change), the checksum no longer matches and Flyway refuses to run any further migrations. This is a safety mechanism to prevent accidental changes to already-applied migrations, but it commonly causes issues when developers edit migration files for formatting, when Git line-ending conversions alter files, or when migration files are committed from different machines with different editors.
Symptoms
``` org.flywaydb.core.internal.command.DbMigrate$FlywayMigrateException: Migration V002__create_users_table.sql changed checksum ----------------- Script checksum: Calculated: 1234567890 Recorded: 0987654321
Flyway attempted to validate the migration script against the recorded checksum, but they did not match. ```
Application fails to start:
``` ******* APPLICATION FAILED TO START *******
Description:
Flyway migration validation failed: Migration V002__create_users_table.sql has changed since it was applied. ```
Common Causes
- Editing an already-applied migration file: Changing SQL content, comments, or even whitespace
- Git line-ending conversion: CRLF vs LF changes the file content and checksum
- Different Flyway versions: Flyway 9 and Flyway 10 may calculate checksums differently
- Migration file committed from different machine: Different editor adds trailing newline or BOM
- Manual database changes: Someone modified the database schema outside of Flyway
- Merge conflict resolution: Git merge changes the migration file content
Step-by-Step Fix
Step 1: Use Flyway repair to fix the checksum
If the migration content is intentionally the same (only whitespace changed):
```bash # With Flyway CLI flyway repair
# With Maven mvn flyway:repair
# With Gradle gradle flywayRepair
# With Spring Boot # Set this property to enable repair on startup (use with caution!) spring.flyway.repair-on-migrate=true ```
This updates the checksum in flyway_schema_history to match the current file.
Step 2: Use baseline for existing databases
If the database was modified outside of Flyway:
```sql -- Check current state SELECT * FROM flyway_schema_history ORDER BY installed_rank;
-- Baseline the database at the current state flyway baseline -baselineVersion=001 -baselineDescription="Baseline" ```
Or in Spring Boot:
spring:
flyway:
baseline-on-migrate: true
baseline-version: "001"Step 3: Use repeatable migrations for changing scripts
For scripts that change frequently (stored procedures, views, functions), use repeatable migrations:
-- db/migration/R__update_user_view.sql
CREATE OR REPLACE VIEW user_summary AS
SELECT u.id, u.name, u.email,
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, u.email;Repeatable migrations (prefixed with R__) are re-executed every time their checksum changes, without causing a mismatch error.
Step 4: Prevent future checksum changes
Add a pre-commit hook:
```bash #!/bin/bash # .pre-commit-hooks/check-migration-files.sh # Prevent changes to already-applied migration files APPLIED_MIGRATIONS=$(find src/main/resources/db/migration -name "V*.sql" | sort)
for file in $APPLIED_MIGRATIONS; do if git diff --cached --name-only | grep -q "$(basename $file)"; then echo "ERROR: Cannot modify already-applied migration: $(basename $file)" echo "Create a new migration file instead." exit 1 fi done ```
Prevention
- Never edit a migration file once it has been applied to any environment
- Create a new migration file for any schema changes, even to fix mistakes
- Use
R__repeatable migrations for views, stored procedures, and functions - Configure Git with
*.sql text eol=lfin.gitattributesto prevent line-ending changes - Add
flyway validateto your CI pipeline to catch checksum issues before deployment - Document the migration workflow in your team wiki: "create new file, never edit existing"