テックブログ

Flywayのchecksum mismatchとは?原因と安全な直し方

Flywayのchecksum mismatchとは?原因と安全な直し方

Flywayのchecksum mismatchとは、データベースへマイグレーションを適用した時点で履歴に記録されたchecksumと、現在配置されているマイグレーションファイルから計算されたchecksumが一致しない状態です。代表的な原因は、すでに適用済みのV1__create_users.sqlなどを後から編集したことです。これは必ずしも「DBが壊れた」という意味ではなく、「過去に適用した内容と現在のファイルが同じではない可能性がある」という重要な警告です。エラーを消すためにすぐrepairを実行するのではなく、Gitの差分、flyway_schema_history、実際のDBスキーマを確認し、なぜ差分が生じたのかを理解してから対応する必要があります。

1. Flywayのchecksum mismatchとは

1-1. Flywayがchecksumを記録する理由

Flywayがchecksumを記録する理由は、過去にDBへ適用したマイグレーションと、現在プロジェクトに存在するマイグレーションが同じ内容かを確認するためです。ファイル名やバージョンが同じでも、中身が変更されていれば別の内容として検知できます。

Versioned Migrationを適用すると、Flywayはそのマイグレーションに関する情報をSchema History Tableへ記録します。標準的な構成ではflyway_schema_historyというテーブルが使われ、バージョン、説明、スクリプト名、checksum、適用日時、成功状態などが管理されます。

例えばV1__create_users.sqlを適用したとき、その時点の内容に対応するchecksumが履歴へ記録されます。次回以降、Flywayは現在のV1から求めたchecksumと履歴上の値を比較できるため、「V1という名前は同じだが、内容が後から変わっている」という状態を見つけられます。

1-2. 適用時と現在のファイルが違うとエラーになる

一度適用したVersioned Migrationを後から書き換えると、適用時のchecksumと現在のchecksumが異なり、validateなどでchecksum mismatchとして検出されることがあります。

最初に、次のV1__create_users.sqlをDBへ適用したとします。

CREATE TABLE users (
    id BIGINT PRIMARY KEY,
    name VARCHAR(100) NOT NULL
);

何をしているのか: usersテーブルを作成し、idnameを定義しています。この内容でV1が適用されると、そのマイグレーションの情報とchecksumが履歴へ記録されます。

その後、「emailも必要だった」と気付き、同じV1を次のように編集したとします。

CREATE TABLE users (
    id BIGINT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(255)
);

何をしているのか: V1のファイルそのものへemailカラムを追加しています。しかし既存DBでは、編集前のV1しか実行されていません。

状態を図にすると次のようになります。

V1を最初に適用
    ↓
V1__create_users.sql
    ↓
DBに users(id, name) を作成
    ↓
flyway_schema_history
へV1のchecksumを記録
    ↓
開発者がV1のSQLを書き換える
    ↓
現在のV1には email も存在
    ↓
validate
    ↓
履歴のchecksum ≠ 現在のchecksum
    ↓
checksum mismatch

現在のファイルにemailが書かれていても、すでにV1を適用したDBへその変更が自動的に追加されるわけではありません。この「DBへ実際に適用された変更」と「Git上で現在見えている変更」のずれこそ、checksum mismatchを軽視してはいけない理由です。

1-3. checksum mismatchは何を知らせているのか

checksum mismatchは、「適用済みとして記録されているマイグレーションと、現在利用できる同じマイグレーションの内容が一致していない」ことを知らせるシグナルです。それだけでDB破損を意味するものではありません。

Flywayから見ると、過去にどのSQLがDBへ適用されたのかと、現在のファイルが同一であるという前提を確認できなくなっています。この状態で履歴だけを現在のファイルに合わせると、実際のDB構造とマイグレーション履歴の意味がずれる可能性があります。

したがって最初に考えるべきことは「どうやってエラー表示を消すか」ではなく、「なぜファイルが変わったのか」「どの内容が実際にDBへ適用されたのか」です。意図しない編集であれば元に戻せる可能性がありますし、本当に新しいDB変更が必要なら、新しいVersioned Migrationとして追加するのが基本です。

2. checksum mismatchが発生する代表的な原因

2-1. 適用済みマイグレーションを書き換えた

最も分かりやすい原因は、すでにDBへ適用したVersioned Migrationを後から編集することです。同じバージョン番号でも内容が変化するため、保存済みchecksumと一致しなくなります。

例えばV1適用後に「NOT NULLを付け忘れた」「カラムが1つ足りなかった」と気付き、V1を直接修正すると発生し得ます。新しいDBをゼロから作れば修正版V1が実行される一方、既存DBでは古いV1がすでに適用済みです。

この状態を放置すると、新規環境と既存環境が同じV1を「適用済み」と表示しながら、実際のスキーマが違う可能性があります。そのため、共有済みのVersioned Migrationは基本的に変更せず、追加変更はV2以降として表現します。

2-2. Git操作などで異なる内容のファイルへ置き換わった

自分が直接SQLを編集していなくても、Gitのブランチ切り替え、rebase、merge、cherry-pickなどによって、同じ名前のマイグレーションファイルが異なる内容へ置き換わる場合があります。

例えば自分のローカルDBにはブランチAのV1が適用されているのに、ブランチBへ切り替えた結果、同じV1__create_users.sqlの内容が異なる状態になるケースです。DBはそのままなので、履歴はブランチA、ファイルはブランチBという組み合わせになります。

この場合、Flywayの問題というより、DBと現在のGit作業ツリーが別の履歴を参照していることが原因です。ローカルの使い捨てDBであれば再作成が合理的な場合もありますが、共有DBや本番DBで同じ判断をしてはいけません。

2-3. 環境ごとにマイグレーションファイルの状態が異なる

開発・検証・本番で異なるバージョンのアプリケーションやマイグレーションファイルを使っている場合も、整合性問題の原因になります。

例えば開発環境ではV1を書き換えた最新ブランチを使用し、本番環境には変更前V1を含むリリースが適用済みだったとします。同じ「V1」という名前でも、環境によってファイル内容が異なることになります。

Flywayを安定運用するには、DBだけでなく「どのGitコミット・リリースに含まれるマイグレーションを使ったか」も重要です。checksum mismatchが特定環境だけで発生する場合は、その環境で実行しているアプリケーション成果物やマイグレーションファイルも確認します。

3. validateで何を確認しているのか

3-1. 履歴と現在のマイグレーションを比較する

validateは、Flywayが管理しているマイグレーション履歴と、現在利用可能なマイグレーションの整合性を確認するための処理です。新しいDB変更を適用するための処理ではありません。

概念的には、DB側のSchema History Tableと、現在設定されたlocationsなどからFlywayが検出したマイグレーションを比較します。その結果、適用済みマイグレーションと現在のファイルに不整合がないかを確認します。checksum mismatchはvalidateで検出される問題の一つであり、ほかにもMigration名や種類、適用状況などの不整合が確認されます。

コマンドライン環境では、例えば次のように実行します。

flyway validate

何を確認するコマンドなのか: 適用履歴と現在のマイグレーションの整合性を検証します。DBスキーマを新しい状態へ変更するコマンドではありません。

3-2. checksumの不一致を検出する

validateでは、適用済みマイグレーションについて記録済みchecksumと現在のchecksumが異なる状態を検出できます。これにより、適用後のファイル変更に気付きやすくなります。

例えば履歴を単純化すると、次のような状態です。

flyway_schema_history
V1 checksum = 123456

一方、現在のファイルをFlywayが読み取った結果が次のようになったとします。

V1__create_users.sql
現在のchecksum = 987654

この場合、Flywayは同じV1について不一致が存在すると判断できます。実際のchecksum値そのものを人が暗記したり、手計算したりする必要はありません。重要なのは「過去に適用した内容と現在の内容が同じかをチェックするための値」だと理解することです。

3-3. validateはエラーを自動修復する機能ではない

validateは問題を検出するための機能であり、検出した不一致を自動的に修復する機能ではありません。ここをrepairと混同しないことが重要です。

checksum mismatchが検出されたとしても、validateがV1を以前の内容へ戻したり、DBへ不足しているemailカラムを追加したりすることはありません。あくまで整合性に問題があることを知らせます。

validaterepairの違いを整理すると次のようになります。

操作主な役割DBスキーマへの新規変更履歴情報への影響
validate履歴と現在のマイグレーションを検証する変更を適用する目的ではない検証が中心
repairSchema Historyの特定の問題を修復・再調整する現在のSQLをDBへ適用する処理ではない失敗履歴の除去やメタデータの再調整などを行う
migrate未適用マイグレーションを実行する未適用変更を適用する適用結果を履歴へ記録する

checksum mismatchを見つけたときは、まずvalidateが何を警告しているかを調査し、その原因に応じた対応を選びます。

4. checksum mismatchが発生したときの確認手順

4-1. エラーになったマイグレーションを特定する

最初に、どのVersioned Migrationで不一致が発生しているのかを特定します。複数のファイルを同時に触る前に、問題の対象を絞ることが重要です。

Flywayのvalidationエラーには、問題となったマイグレーションのバージョンやchecksumに関する情報が表示されることがあります。まずエラーメッセージを読み、V1なのかV2なのかを確認します。

例えばV1のchecksum mismatchなら、最初に調べる対象はV1__create_users.sqlです。エラーを消す目的で他のマイグレーションやflyway_schema_historyまで変更してしまうと、原因調査がさらに難しくなります。

4-2. Gitの履歴とファイル差分を確認する

対象を特定したら、次にGitでマイグレーションファイルがいつ、どのように変わったかを確認します。意図しない編集なら、ここで原因が判明することがあります。

例えば次のようなコマンドが役立ちます。

git log --follow -- path/to/V1__create_users.sql

何を確認するコマンドなのか: V1ファイルに関するGit上の変更履歴を確認します。FlywayやDBの状態を書き換えるコマンドではありません。

現在の変更差分を見る場合は、例えば次のように確認できます。

git diff -- path/to/V1__create_users.sql

何を確認するコマンドなのか: 現在の作業ツリーでV1がどう変更されているかを確認します。

重要なのは、「修正版のほうが正しそうだから」という理由だけで現在ファイルを正として扱わないことです。共有環境へ古い内容がすでに適用されているなら、その事実も含めて対応を考える必要があります。

4-3. flyway_schema_historyと実際のDB状態を確認する

Gitを確認した後は、Flywayの履歴と実際のDBスキーマを確認します。「履歴上どうなっているか」と「DBが実際にどうなっているか」を分けて見ることが重要です。

flyway_schema_historyでは、対象バージョン、スクリプト、checksum、適用日時、成功状態などを確認できます。参照目的でSELECTするのであれば、例えば次のようなイメージです。

SELECT
    version,
    description,
    script,
    checksum,
    installed_on,
    success
FROM flyway_schema_history
WHERE version = '1';

何を確認しているのか: V1についてFlywayが記録している履歴を確認しています。ここで手作業のUPDATEを実行することを通常の復旧方法としては扱いません。

さらにDB側でusersテーブルに本当にemailがあるのかなど、実際のスキーマも確認します。

現在のV1ファイル
users(id, name, email)

        ↓ 比較

実際の既存DB
users(id, name)

この状態なら、単に履歴checksumだけを現在のV1へ合わせてもemailはDBへ追加されません。checksum、ファイル、実DBの3つを確認して初めて安全な判断ができます。

5. Flywayのrepairとは

5-1. repairが行う処理を理解する

repairは、FlywayのSchema History Tableに存在する特定の問題を修復・再調整するための機能です。checksum mismatch専用でも、あらゆるFlywayエラーを自動修復する万能コマンドでもありません。

現行のrepairには、主に次の役割があります。

  • 失敗したMigrationの履歴をSchema History Tableから除去する
  • 適用済みMigrationのchecksum、description、typeを、現在利用可能なMigrationに合わせて再調整する
  • DBには適用履歴があるものの、現在のlocationsでは見つからないMigrationをDeletedとして扱う

コマンドラインでは次のように実行する形があります。

flyway repair

何を変更するコマンドなのか: FlywayのSchema Historyに対して修復・再調整を行います。現在のSQLファイルを改めてDBスキーマへすべて適用するコマンドではありません。また、repairを実行するときは、対象Migrationを正しく判定できるように、migrateと同じMigration locationsを参照する必要があります。

5-2. checksumを現在の内容へ合わせる場合がある

checksum mismatchに対してrepairを実行すると、履歴上のchecksumを現在のマイグレーション内容に合わせる処理が行われる場合があります。だからこそ、実行前の原因確認が重要です。

先ほどの例で、

DBへ実際に適用されたV1:
CREATE TABLE users (
    id,
    name
)

なのに現在のV1が、

現在のV1:
CREATE TABLE users (
    id,
    name,
    email
)

となっている状態を考えます。

ここで履歴のchecksumだけを現在V1へ合わせると、Flyway上は「現在のV1と履歴が一致している」状態に近づいても、既存DBへemailが自動追加されるわけではありません。

つまり、validationエラーが消えることと、DBが期待したスキーマになっていることは別問題です。これを理解せずrepairを使うと、本来検知すべき差異を履歴上だけ解消してしまう可能性があります。

5-3. repairしてもDBスキーマそのものは元に戻らない

repairを実行しても、誤って変更されたSQLを自動修正したり、実際のDBスキーマを期待する形へ自動変更したりするわけではありません。

Flywayの履歴管理とDBスキーマ変更は分けて考える必要があります。DBへ新しいカラムを追加したいのであれば、通常はそのための新しいVersioned Migrationを作り、migrateで適用します。

repair自体が危険なコマンドというわけではありません。ただし、checksum mismatchの原因を理解しないまま実行すると、実際のDB状態とMigration履歴のずれを見えにくくする可能性があります。履歴を現在のMigrationへ合わせることが正しいと確認できた場合に使い、本番・共有環境ではチームの変更管理、承認、バックアップ、復旧手順などのルールを優先してください。

6. checksum mismatchを安全に直すには

6-1. まずファイルを本来の内容へ戻せるか確認する

適用済みVersioned Migrationを誤って編集しただけなら、まずファイルを適用時の内容へ戻せないか確認します。履歴と実際のDBが正しく、現在ファイルだけが誤っているなら、この方法が最も自然です。

例えばGit履歴から、V1適用時の内容が次だったことを確認できたとします。

CREATE TABLE users (
    id BIGINT PRIMARY KEY,
    name VARCHAR(100) NOT NULL
);

現在のV1に誤ってemailを追加していたなら、V1をこの元の内容へ戻します。これにより現在ファイルのchecksumが適用時と再び整合する可能性があります。

ただし、Git履歴やFlywayの設定、使用しているファイルの状態など、不一致の原因によって対応は変わります。「V1を何となく似たSQLへ戻せばよい」のではなく、適用時の正しいソースを確認することが重要です。なお、SQL Migrationのchecksum計算では行末コードの違いが無視されるため、LFとCRLFの違いだけを通常のchecksum mismatchの原因として扱うべきではありません。

6-2. 必要なDB変更は新しいマイグレーションとして追加する

V1適用後に本当にemailカラムが必要になったのであれば、V1を書き換えず、新しいV2として変更を追加するのが基本です。

V1は適用時の状態へ戻します。

-- V1__create_users.sql
CREATE TABLE users (
    id BIGINT PRIMARY KEY,
    name VARCHAR(100) NOT NULL
);

そして新しくV2を追加します。

-- V2__add_email_to_users.sql
ALTER TABLE users
ADD COLUMN email VARCHAR(255);

何をしているのか: V1を「usersテーブルを最初に作った変更」として保持し、その後のemail追加をV2として新しい履歴にしています。

なぜ必要なのか: 既存環境でも新規環境でも、「V1でテーブル作成 → V2でemail追加」という同じ変更履歴を再現できるようにするためです。

既存DB

V1 適用済み
    ↓
V2 を新規追加
    ↓
migrate
    ↓
emailカラムを追加
新規DB

V1 を適用
    ↓
V2 を適用
    ↓
既存DBと同じ最終スキーマ

このように「過去を書き換える」のではなく「次の変更として積み上げる」ことがVersioned Migrationの基本的な運用です。

6-3. repairを使う場合は理由とDB状態を確認する

repairを使う場合は、なぜ履歴を修復する必要があるのか、そして実際のDB状態が期待どおりなのかを事前に確認します。repairは正当な修復手段ですが、単にvalidateを成功させたいという理由だけで、原因を確認せずに実行しないことが重要です。

実行前には少なくとも次を確認します。

  • checksum mismatchになったバージョンを特定した
  • Flywayのエラーメッセージを確認した
  • Gitで対象ファイルの変更履歴を確認した
  • 適用時のMigration内容を確認した
  • flyway_schema_historyの対象履歴を確認した
  • 実際のDBスキーマが期待どおりか確認した
  • ファイルを適用時の内容へ戻す方法と、新しいMigrationを追加する方法を検討した
  • repairで変更される履歴情報を理解した
  • repairがDBスキーマそのものを修正しないと理解した
  • repairmigrateと同じMigration locationsを参照していることを確認した
  • 本番・共有環境ではチームの承認、バックアップ、復旧手順を確認した

例えば、意図的に内容を変更したMigrationへ履歴を合わせることがチーム内で合意され、実際のDB状態との整合性も確認できているなら、repairが適切な場合があります。一方、現在のファイルへ書かれた変更がDBに適用されていないなら、履歴だけを合わせず、新しいMigrationで必要な変更を適用する方針を検討します。

ローカルの使い捨てDBなら、DBを再作成して現在のMigrationを最初から適用する方が分かりやすい場合もあります。ただし、本番・共有DBでは同じ対応を安易に選べません。環境の性質に合わせて判断し、原因と対応内容を説明できる状態で作業することが重要です。

7. まとめ

7-1. checksum mismatch発生時の対応フロー

Flywayのchecksum mismatchは、適用時に記録されたchecksumと、現在のMigrationから計算されたchecksumが一致しない状態です。DB破損を直接示すものではありませんが、適用済みの変更と現在のファイルに差異があることを知らせています。

発生時は、次の順序で確認します。

checksum mismatchを確認
    ↓
対象のMigrationを特定
    ↓
Git履歴とファイル差分を確認
    ↓
flyway_schema_historyを確認
    ↓
実際のDBスキーマを確認
    ↓
原因と正しい状態を判断
    ↓
ファイルを適用時の内容へ戻す
または
新しいMigrationを追加する
または
根拠を確認したうえでrepairする

大切なのは、エラーを消す操作から始めるのではなく、どの内容がDBへ適用され、なぜ現在のファイルと異なっているのかを確認することです。そのうえで、適用時の内容へ戻す、新しいMigrationを追加する、または履歴を現在のMigrationへ合わせるためにrepairする、という選択肢から適切な対応を選びます。

7-2. 適用済みマイグレーションを扱うときのチェックリスト

checksum mismatchは単に消すべきエラーではなく、履歴と現在状態のずれを知らせる情報として利用します。

実装・運用時には、次の項目を確認してください。

  • checksumが適用済みマイグレーションの整合性確認に使われることを理解している
  • flyway_schema_historyに適用履歴が保存されることを理解している
  • checksum mismatchをDB破損と即断していない
  • mismatchになったマイグレーションを特定した
  • 適用済みVersioned Migrationを編集していないか確認した
  • Git履歴とdiffを確認した
  • ブランチ切り替えなどによるファイル差し替えを確認した
  • 環境ごとに異なるマイグレーションを利用していないか確認した
  • validateがchecksum以外のMigration名・種類・適用状況なども検証することを理解している
  • validateがDBを修正する機能ではないと理解している
  • repairを原因確認前の最初の対応として実行していない
  • repairが履歴を修復・再調整する正当な手段である一方、万能なエラー修復機能ではないと理解している
  • repairでDBスキーマが現在SQLどおりに自動変更されると誤解していない
  • repairmigrateと同じMigration locationsを参照していることを確認した
  • flyway_schema_historyを手作業でUPDATEしていない
  • 実際のDBスキーマを確認した
  • ファイルを適用時の内容へ戻せないか検討した
  • 本当に必要な変更は新しいV2以降として追加した
  • ローカルDBと本番・共有DBで対応方法を分けて考えている
  • 本番では原因不明のままrepairしていない
  • 本番・共有環境ではチームの変更管理と承認ルールを優先している
  • 必要に応じてバックアップや復旧手順を確認している
  • 使用中Flywayバージョンの公式ドキュメントでvalidaterepairの挙動を確認している

checksum mismatchで最も重要なのは、エラーをすぐ消すことではありません。「過去にDBへ適用した変更」と「現在Git上に存在する変更」がなぜ異なっているのかを説明できる状態に戻すことです。Flywayの履歴、Git、実際のDBスキーマを照合し、本来必要な変更は新しいマイグレーションとして積み上げることが、安全なDB変更管理につながります。

8. 参考リンク

使用しているFlywayバージョンに対応するRedgate公式ドキュメントもあわせて確認してください。