インフラの設計図(ステートファイル)が破損したとき
重要なデプロイの最中、あるいはトラフィックの急増に備えてリソースをスケーリングしている最中だとしましょう。terraform plan を実行したところ、いつものサマリーではなく、ターミナルに謎のエラーが表示されました。管理しているすべてのリソースの公式な記録であるステートファイルが読み取り不能になってしまったのです。
Error: Failed to decode state file
The state file could not be decoded: invalid character 'x' looking for beginning of value
このメッセージは、Terraform の JSON パーサーが予期しない文字に遭遇したことを示しています。エラーに含まれる 'x' は重要な手がかりです。それは Git のマージコンフリクトによる < かもしれませんし、システムクラッシュ後の \x00 ヌルバイトの羅列、あるいはテキストエディタによる隠れた BOM(バイトオーダーマーク)かもしれません。1万行のステートファイルの中にカンマが1つ紛れ込んでいるだけで、パイプラインは停止してしまいます。
ステップ 1:緊急バックアップを作成する
修復を試みる前に、直ちに現在のステートファイルをバックアップしてください。破損したファイルでも 99% は正確なデータです。復旧に失敗した場合に備えて、元のデータに戻せるようにしておく必要があります。以下のコマンドを実行して、タイムスタンプ付きのコピーを保存してください。
cp terraform.tfstate terraform.tfstate.corrupt.$(date +%F_%H%M%S)
AWS S3 や HashiCorp Cloud などのリモートバックエンドを使用している場合は、ローカルの .terraform/ ディレクトリを確認してください。そこに無傷のキャッシュバージョンが残っている可能性があります。
ステップ 2:破損箇所を特定する
VS Code や Sublime Text などのコードエディタで terraform.tfstate ファイルを開きます。ほとんどの破損は 3 つの特定のシナリオから発生します。まず、<<<<<<< HEAD のような Git のマージコンフリクトマーカーがないか確認してください。これは、誰かが誤ってステートファイルをバージョン管理にコミットしたときに発生します。次に、書き込みの中断を確認します。ファイルが ^@^@^@ という文字の羅列で突然終わっている場合、ディスクへの書き込み中にプロセスが強制終了した可能性があります。
3 つ目は、手動編集による構文エラーです。ブラケット(括弧)の閉じ忘れや不要な引用符が 1 つあるだけで、構造全体が壊れます。数千行の中から正確な行を見つけるには、バリデーターを使用することをお勧めします。ToolCraft の JSON Formatter & Validator などが便利です。これはブラウザ上ですべての処理を行うため、IP アドレスやリソース ID などの機密情報を含むステートファイルを外部サーバーにアップロードせずに済みます。
ステップ 3:復旧戦略
オプション A:自動セーフティネットを使用する
Terraform には保護機能が組み込まれています。インフラの変更に成功するたびに、直前のバージョンが terraform.tfstate.backup として保存されます。メインのファイルが読み取れない場合は、jq を使用してバックアップの整合性を確認してください。
# ファイルが有効な JSON であれば何も出力されません
cat terraform.tfstate.backup | jq . > /dev/null
# 有効な場合は、復元します
mv terraform.tfstate.backup terraform.tfstate
オプション B:リモートからのプルを強制する
リモートバックエンドを使用しているチームの場合、ローカルコピーが単に破損したキャッシュである可能性があります。ローカルのステートを削除し、ストレージバケットから新しいコピーをプルすることで解決できることがよくあります。
rm terraform.tfstate
terraform init -reconfigure
terraform state pull > terraform.tfstate
オプション C:手動による JSON 修正
リモートのステートも破損している場合(CI/CD ジョブが誤って破損したファイルをプッシュした場合など)、手動で修正する必要があります。Git のコンフリクトマーカーを削除し、正しいリソースブロックを選択してください。ファイルが閉じ括弧 } で終わっていること、および各リスト項目がカンマで区切られていることを確認します。編集後は、必ず JSON リンターで構造が有効であることを確認してください。
ステップ 4:動作確認(スモークテスト)
ファイルが修正されたと思ったら、安全なコマンドで検証します。まだ terraform apply は実行しないでください。代わりに terraform state list を実行します。これは読み取り専用の操作であり、Terraform にファイル全体の解析を強制します。エラーなしでリソースのリストが返されれば、デコードの問題は解決しています。その後に terraform plan を実行し、復元されたステートがクラウド環境の実際のリソースと一致するか確認してください。
予防策:破損を未然に防ぐ
- .tfstate を Git で管理しない: ステート破損の主な原因です。必ず S3 と DynamoDB テーブルの組み合わせなど、ステートロック機能を備えたリモートバックエンドを使用してください。
- バケットのバージョニングを有効にする: S3 や GCS にステートを保存する場合は、そのバケットのバージョニングを有効にしてください。これにより、破損したステートを数秒でロールバックできます。
- 直接編集を避ける: 変更には
terraform state rmやterraform state mvを使用してください。どうしても手動で JSON を編集する必要がある場合は、構文を壊さないよう、プライバシーに配慮したバリデーターを必ず使用してください。

