terraform state lock エラーの解決 — 原因の確認と force-unlock の判断基準
terraform plan や apply を実行したら、次のエラーが出ました。
Error: Error acquiring the state lock
Error message: operation error S3: PutObject, ...
Lock Info:
ID: b2f1c4d8-...
Path: myapp-tfstate/myapp/prod/terraform.tfstate
Who: bob@bobs-laptop
Created: 2026-09-17 02:14:33 UTC結論を先に置きます。このエラーの大半は故障ではなく正常な動作であり、最初の対応はコマンドではなく待つことです。ロックは、2 つの実行が同じ state を同時に書き換える事故を防ぐために Terraform が意図的にかけているものだからです。問題は、残ってはいけない状況でロックが残っている少数のケースで、この記事はその 2 つを見分けるための手順です。
まず Lock Info を読みます #
判断材料はエラー本文の Lock Info にすべて揃っています。
- Who: ロックをかけた実行主体です。同僚のアカウントならその人の apply が進行中の可能性が高く、CI ランナーの名前ならパイプラインが動いています。
- Created: ロックがかかった時刻(UTC)です。数分前なら進行中の確率が高く、数時間・数日前なら残留ロックを疑えます。
- ID: ロックの識別子です。解除コマンドに必要なのでコピーしておきます。
原因は 3 つのうちどれかです #
- 他の人や CI が実行中(正常): いちばん多いケースです。apply はリソースによっては数十分かかることがあるので(RDS の作成など)、Created が最近なら、終わるのを待つのが正解です。
- 実行が異常終了してロックだけが残った: ターミナルの強制終了、ノート PC のスリープ、CI ランナーの強制キャンセルが原因です。実行は死んだのにロック解除の段階まで到達できなかったケースで、手動解除が必要なのはこの場合だけです。
- 権限の問題でロックの確認自体が失敗している: Lock Info なしでアクセス拒否系のメッセージが出るなら、ロックではなく認証情報や IAM の問題です。この記事の範囲外なので、state バケットへのアクセス権限を先に確認します。
解除の判断手順 #
順番に確認し、すべて通過したときだけ解除します。
- Who に直接確認します。 実行中だという返事なら待ちます。CI ランナーなら該当パイプラインの実行状況画面を確認します。
- Created が十分に古いかを見ます。 チームでいちばん長い apply の時間(ふつう数十分)より古いロックなら、残留の可能性が高いです。
- 両方確認できたら、ロック ID で解除します。
terraform force-unlock b2f1c4d8-...ID は Lock Info の値をそのまま使います。解除後に plan を 1 回回して state が無事なことを確認すれば完了です。
force-unlock を安易に使ってはいけない理由 #
このエラーを検索すると「force-unlock すればいい」という答えが多く出てきますが、確認手順なしで使うのは危険です。進行中の apply のロックを外して自分の apply を始めると、2 つの実行が同じ state を同時に書き込む状況になります。ロックが防ごうとしていた、まさにその事故です。片方の記録が上書きされると state と実際のインフラが食い違い、その復旧はロック待ちとは比べものにならないほど骨の折れる作業になります。force-unlock は「実行者がいないことを確認したあとの最終手段」という位置づけを守るべきです。
DynamoDB ロック方式の場合 #
S3 バックエンドのロックには、現行標準の use_lockfile = true(state の隣の .tflock オブジェクト)のほかに、旧標準の DynamoDB テーブル方式(dynamodb_table 引数)がまだ多く残っています。動作と判断手順は同じで、残留ロックの実体が違うだけです。DynamoDB 方式では指定したテーブルの LockID 項目がロックであり、force-unlock が失敗する例外的な状況では、コンソールで該当項目を直接確認できます。2 つの方式の違いと移行は Terraform 基礎 #9で扱いました。
再発を減らす #
残留ロックの定番の原因は、人による強制終了と CI の同時実行です。人の側は apply を途中で切らない習慣(切らざるを得ないなら、Terraform に片付ける時間を与える Ctrl+C の 1 回まで)、CI の側は同じ state を触るジョブを直列化する concurrency 設定が答えです。CI ワークフローの構成は Terraform 運用 #1に整理してあります。
まとめ #
- state lock エラーの大半は正常なシグナルです。最初の対応は force-unlock ではなく Lock Info の確認と待機です
- Who に確認し、Created がチームの最長 apply 時間より古いときだけ残留ロックと判断します
- 解除は
terraform force-unlock <ロックID>で、進行中の実行のロックを外すと state の同時書き込み事故になります - DynamoDB 方式はロックの実体がテーブル項目という点だけが違い、判断手順は同じです
- 再発防止は apply を切らない習慣と、CI の concurrency による直列化です