Spring Boot Flyway Checksum Mismatch and Validate Failed: Repair Guide

I often get asked about Spring Boot freezing on startup with errors like Migration checksum mismatch for migration version 3 or Validate failed: Detected failed migration to version 5. Both indicate Flyway blocking startup during pre-startup validation, but the causes and remedies are completely different. This article covers how to distinguish between the two errors, how to try flyway repair locally, why you should never casually run repair in production, and the steps for manually fixing the flyway_schema_history table — all organized by symptom.

Distinguishing the two error messages

First, read the logs carefully.

ERROR: Migration checksum mismatch for migration version 3
-> Applied to database : -874034534
-> Resolved locally    : 1198598178

ERROR: Validate failed: Detected failed migration to version 5 (add_index)

The first is a checksum mismatch. It means the content of an already-applied migration file no longer matches the checksum recorded in the database. The second is a Detected failed migration, indicating that a failed record with success = false remains in flyway_schema_history. In both cases, the Validate process is simply blocking startup, but the underlying causes differ, so first check which log message you’re actually seeing. Sometimes both appear at once.

Typical causes of a changed checksum

The causes of a checksum mismatch generally fall into one of these categories:

  • An already-applied migration file (e.g., V3__xxx.sql) was edited afterward
  • Line endings (CRLF/LF) or character encoding changed due to differences in Git configuration or OS
  • Migration files are dynamically generated or formatted during CI/CD builds, causing slight content variation on each run
  • Upgrading the Flyway version or a plugin changed what gets included in the checksum calculation

The first cause is by far the most common. Even “just fixing a typo” changes the checksum, which is exactly why the rule of never touching an already-applied file matters so much.

First, check the current state with flyway info

Before running repair, objectively check the situation with flyway info.

./gradlew flywayInfo
# or
mvn flyway:info

Looking at the State column in the output tells you which versions are Success, which are Failed, and which are flagged with a checksum mismatch. In production, the first thing you should do is just this info check — do not run repair or migrate, which involve writes, yet.

Trying flyway repair in a local environment

If you know the cause is a local mistake, try repair in your development environment.

./gradlew flywayRepair
# for the Flyway CLI
flyway repair -url=jdbc:postgresql://localhost:5432/mydb -user=dev -password=dev

Comparing flyway info before and after, you’ll see that the version with the checksum mismatch has changed to Success and the failure record has been removed.

What flyway repair actually does

This is the point most people misunderstand. repair only does the following two things:

  1. Rewrites the checksum in flyway_schema_history to match the content of the migration file currently on disk
  2. Deletes failure records where success = false

In other words, it only makes the file and the database record consistent — it does not check at all whether the actual table structure or data is correct. Since startup succeeds once the checksums match, this command is easy to mistake for something that “fixed” the problem.

Why you should never run repair in production without thinking

Forgetting this nature of repair and running it carelessly in production is dangerous. For example, if V5__add_index.sql failed partway through execution, the actual table might only have half the intended index created. If you run repair in this state, the history gets marked as successful, and the discrepancy from reality (schema drift) is simply hidden. What production actually needs is not aligning the checksum, but actually verifying that the current schema is as intended.

Production recovery procedure

1. Take a backup

Before doing anything, always back up the flyway_schema_history table itself.

CREATE TABLE flyway_schema_history_backup_20260929 AS
SELECT * FROM flyway_schema_history;

If possible, also back up the entire target schema, and keep a log of the flyway info output at this point.

2. Check the table structure

The main columns are as follows.

ColumnMeaning
installed_rankApplication order
versionMigration version number
checksumHash value computed from file content
successWhether the migration applied successfully
installed_byThe DB user who ran it

It’s generally the rows with success = false that are blocking startup.

3. Manually UPDATE/DELETE

Always check the target records first before operating on them.

SELECT * FROM flyway_schema_history WHERE success = false;

-- After visually confirming the actual table, if the partially applied
-- change has already been manually reflected in the DB, delete the failure record
DELETE FROM flyway_schema_history WHERE version = '5' AND success = false;

-- When the file content is correct but only the checksum is out of sync
UPDATE flyway_schema_history
SET checksum = 1198598178
WHERE version = '3';

After running DELETE or UPDATE, always visually verify with SQL that the target tables and columns actually exist before starting the application. Skipping this step means you’d be deploying to production with only the appearance of consistency.

Rules to prevent recurrence

  • Never edit an already-applied migration file. Fix issues by adding a new version file instead
  • Run flyway validate in the CI pipeline to detect checksum mismatches before merging
  • Standardize line endings and character encoding across the entire repository with .gitattributes
- name: Flyway Validate
  run: ./gradlew flywayValidate

Summary

A checksum mismatch is a discrepancy between the file and the database record, while a Detected failed migration is a leftover failure record — the causes are completely different. Repair is convenient, but it only aligns the checksum, so in production always pair it with a flyway info status check and a visual verification of the actual tables. If you want to revisit your Flyway setup from the ground up, see Managing Database Migrations with Flyway in Spring Boot, and for general startup-failure triage, see Diagnosing and Fixing Spring Boot Application Startup Failures. If you’re deciding between Flyway and Liquibase, check out Managing Database Migrations with Liquibase in Spring Boot.