TL;DR
変更内容に応じて、以下のどちらかを実行してください:
# バケットまたはキーパスが変更された場合はステートを移行する
terraform init -migrate-state
# 認証情報またはマイナーな設定のみ変更された場合はコンフィグを更新するだけでよい
terraform init -reconfigure
バケットまたはパスが変更された場合は -migrate-state を選択してください。認証情報または重要でない設定のみが変更され、ステートがすでに正しい場所にある場合は -reconfigure を選択してください。
このエラーが発生する原因
Terraformはバックエンド設定のハッシュ値を .terraform/terraform.tfstate 内に保存しています。terraform init を実行するたびに、*.tf ファイルの内容とキャッシュされたハッシュ値を比較します。一致しない場合、Terraformは処理を停止します — 黙って続行することはありません。これは意図的な動作です。誤って間違ったステートバケットを指定してしまうと致命的な結果を招くため、Terraformは変更を明示的に確認するよう求めます。
よくあるトリガーのシナリオ:
- S3バケット名またはGCSバケットを変更した
- バケット内の
key(パス)を変更した - S3バックエンドのAWSリージョンを切り替えた
- バックエンドパスに影響するワークスペースの名前変更または切り替えを行った
- バックエンド設定がローカルキャッシュと異なる他の人のコードをプルした
- ローカルバックエンドからS3/GCSへ(またはその逆に)切り替えた
修正方法1:新しいバックエンドへステートを移行する
ステートの保存場所を変更しましたか?この場合は次のコマンドを使用します:
terraform init -migrate-state
内部では以下の処理が行われます:
- Terraformが古いバックエンドに接続し、既存のステートを読み込む
- そのステートを新しいバックエンドの場所に書き込む
- 処理を実行する前に確認を求める
プロンプトは次のように表示されます:
Initializing the backend...
Do you want to copy existing state to the new backend?
Pre-existing state was found while migrating the previous "s3" backend to the
newly configured "s3" backend. No existing state was found in the newly
configured "s3" backend. Do you want to copy this state to the new backend?
Enter a value: yes
yes と入力すれば、残りはTerraformが処理します。
修正方法2:移行なしで再設定する
バックエンドの設定が変更されたものの、ステート自体はすでに正しい場所にある場合があります。認証情報をローテーションした、AWS CLIプロファイル名を更新した、またはステートの保存場所とは無関係なパラメータを微調整したような場合です。その場合は:
terraform init -reconfigure
これはステートに一切触れずにローカルキャッシュのハッシュ値を更新します。高速かつ非破壊的です。
**警告:**バケット名やキーパスを実際に変更した場合は -reconfigure を使わないでください。ステートが間違った場所を指すことになり、plan や apply で混乱を招く — 場合によっては危険な — 結果が生じます。
よくあるシナリオ:S3バケットまたはキーの切り替え
変更前(旧設定):
terraform {
backend "s3" {
bucket = "my-tf-state-old"
key = "prod/terraform.tfstate"
region = "us-east-1"
}
}
変更後(新設定):
terraform {
backend "s3" {
bucket = "my-tf-state-new"
key = "prod/terraform.tfstate"
region = "us-east-1"
}
}
実行:
terraform init -migrate-state
実行前に、古いバケットへの読み取りアクセス権と新しいバケットへの書き込みアクセス権があることを確認してください。どちらかの権限が不足すると、コピーの途中で移行が失敗します。
よくあるシナリオ:GCSバックエンドの変更
terraform {
backend "gcs" {
bucket = "my-project-tf-state"
prefix = "terraform/state"
}
}
bucket または prefix を変更した場合も、同じ修正方法です:
terraform init -migrate-state
GCSの移行も同じパターンに従います — Terraformは古いGCSの場所から読み込み、新しい場所に書き込みます。追加の手順は不要です。
エッジケース:部分設定ファイルによるバックエンド設定
バックエンドの値をハードコードせず、init時に渡すチームもあります:
terraform init \
-backend-config="bucket=my-tf-state" \
-backend-config="key=prod/terraform.tfstate" \
-backend-config="region=us-east-1"
または backend.hcl ファイルを使用する方法:
# backend.hcl
bucket = "my-tf-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
terraform init -backend-config=backend.hcl
このファイルが変更された場合も同じエラーが発生します。修正方法:同じコマンドに -migrate-state または -reconfigure を追加します:
terraform init -backend-config=backend.hcl -migrate-state
修正の確認
initが完了したら、2つの簡単なチェックで移行が実際に成功したかどうか確認できます:
# 期待するリソースが表示されるはず
terraform state list
# 予期しない変更がないことを確認
terraform plan
state list にリソースが表示されれば問題ありません。多数のリソースが存在するはずなのに何も返ってこない場合、ステートの移行が行われていません — バケットのIAMパーミッションを確認し、terraform init -migrate-state を再実行してください。
予防のためのヒント
バックエンドの変更は、スプリントの途中で気づかずに行われると最も問題になります。いくつかの習慣でそのリスクを大幅に減らせます:
backend.hclまたはバックエンドブロックをインフラの変更と一緒にコミットしてください。バックエンド設定だけを単独で変更する場合は、事前にチームに伝えましょう。.terraform/が.gitignoreに含まれていることを確認してください — 通常は含まれていますが、再確認しましょう。キャッシュされたバックエンドハッシュをコミットすると、コードをプルしたすべてのチームメンバーに影響します。- バックエンドを変更する前に、ステートのスナップショットを取得してください:
terraform state pull > backup-$(date +%Y%m%d).tfstate。2秒で完了し、問題が発生した場合に何時間もの作業を救えます。 - バックエンド設定がYAMLC IベースのCI変数に格納されている場合、ToolCraftのYAML ↔ JSONコンバーターはパイプラインに適用する前に設定構造を検証するのに便利です — 完全にブラウザ上で動作し、データが外部に送信されることはありません。
簡単な判断フローチャート
- バケット名またはキーパスを変更した場合? →
terraform init -migrate-state - 認証情報、プロファイル、またはマイナーな設定のみ変更した場合? →
terraform init -reconfigure - 他の人のコードをプルしてローカルキャッシュが古くなった場合? →
terraform init -reconfigure(リモートバックエンド自体が変更されていないことが前提) - 初めてローカルバックエンドからリモートバックエンドに切り替える場合? →
terraform init -migrate-stateでローカルのステートファイルをリモートバックエンドにアップロードする

