Terraformを本番運用し始めると、こうした状況に必ず一度は直面します。エラーメッセージは英語で長く、どの行が本当の原因なのか見つけにくい。CI/CDに組み込んでいれば、パイプラインが突然止まって復旧に時間がかかることもあります。
この記事では、Terraformのplan・applyエラーを体系的に調査・解決するための実践手順を解説します。デバッグログ(TF_LOG)の活用、DynamoDBのStateロック解除、ドリフト検出とリカバリ、よくあるエラーパターンの切り分けまで、実際のコマンド出力を交えて説明します。
この記事のポイント
・TF_LOG=DEBUG 設定だけでAPIレベルのエラー原因を特定できる
・DynamoDB Stateロック詰まりはforce-unlockコマンドで安全に解除できる
・terraform plan -refresh-onlyでドリフト(コンソール手動変更)を検出できる
・planエラーの多くは「権限不足」「依存関係の循環」「プロバイダー設定ミス」の3パターンに分類できる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
Terraformのplan・applyエラーを3種類に分類する
Terraformのエラーは大きく3種類に分類できます。この分類を最初に把握しておくと、調査の手順が明確になります。・クラウドプロバイダーのAPIエラー:権限不足(AccessDenied)、リソース上限超過、リージョン指定ミスなど。AWSとTerraformの通信段階で起きる問題です
・tfstate整合性エラー:ローカルのtfstateと実際のAWSリソースの状態が食い違っている(ドリフト)場合や、Stateロックが残っている場合です
・HCLコードの構文・依存エラー:変数の未定義、リソース間の循環依存、プロバイダーバージョンの不整合など、コード自体に問題がある場合です
エラーメッセージの先頭にある
Error: の直後の文言を見て、どの種類かを判断するのが最初のステップです。調査の優先順位は「APIエラー → tfstate整合性 → HCLコード」の順です。APIエラーから始めると、権限やネットワークの問題が素早く解消できます。
TF_LOGでデバッグログを有効にしてエラーを追う
Terraformには組み込みのデバッグログ機能があります。TF_LOG 環境変数を設定するだけで、APIリクエスト・レスポンスの詳細をすべてコンソールに出力できます。1. TF_LOGの設定方法(ログレベル別の使い分け)
TF_LOG は以下の5段階で設定できます。・ERROR:致命的なエラーのみ(デフォルトの挙動に近い)
・WARN:警告を追加表示
・INFO:Terraformの動作フローを確認するのに適する
・DEBUG:APIリクエスト/レスポンスを確認できる。権限エラーの調査に最も使う
・TRACE:内部処理の全ログ(量が多いため、限定した場面で使う)
権限エラーや予期しないAPI動作の調査には
DEBUG が適切です。# TF_LOG を設定して terraform plan を実行する export TF_LOG=DEBUG terraform plan
2. TF_LOG_PATHでログをファイルに保存する
デバッグログはコンソールに大量に出力されるため、ファイルに書き出して後から解析するのが実用的です。# ログをファイルに書き出す export TF_LOG=DEBUG export TF_LOG_PATH=/tmp/terraform-debug.log terraform plan # エラー行だけを抽出して原因を絞り込む grep -i 'error\|access denied\|unauthorized' /tmp/terraform-debug.log
3. APIエラーと権限問題をログで読む
以下は、IAM権限不足のリソース作成時に実際に出力されたデバッグログの抜粋です(アカウントID・リソース名はマスク済み)。2026-06-15T14:23:07.441+0900 [DEBUG] provider.terraform-provider-aws_v5.xx: Response body: {"Code":"AccessDenied","Message":"User: arn:aws:iam::XXXXXXXXXXXX:user/terraform-ci is not authorized to perform: ec2:CreateSubnet on resource: arn:aws:ec2:ap-northeast-1::subnet/*"} 2026-06-15T14:23:07.441+0900 [ERROR] provider: Plugin called logger after being closed: logger: error="dial tcp: lookup provider.registry.terraform.io: no such host"
terraform-ci というIAMユーザーが ec2:CreateSubnet 権限を持っていない」と即座に特定できます。TF_LOGなしの通常エラー出力では「AccessDenied」の一行しか表示されず、どのリソース・どのアクションで失敗したか見えません。調査後は必ず
unset TF_LOG でログ出力を無効にしてください。大量のデバッグログがCI/CDのログに残り続けると、本番の機密情報(API応答)が記録されるリスクがあります。Stateロックが解除されない時の対処
S3バックエンド+DynamoDB State Lockingを使用している環境では、terraform apply が途中でプロセス強制終了した場合や、ネットワーク切断が発生した場合に、ロックが残ったままになることがあります。1. Stateロック詰まりのエラーを確認する
ロックが残っている場合、次のterraform plan や terraform apply を実行すると以下のエラーが出ます。$ terraform apply Acquiring state lock. This may take a few moments... ╷ │ Error: Error acquiring the state lock │ │ Error message: ConditionalCheckFailedException: The conditional request failed │ Lock Info: │ ID: a8f3c2d1-xxxx-xxxx-xxxx-7b9e43f1a2c4 │ Path: s3://my-tfstate-bucket/env/prod/terraform.tfstate │ Operation: OperationTypePlan │ Who: terraform@ci-runner-02 │ Version: 1.7.5 │ Created: 2026-06-15 03:17:42.831 +0000 UTC │ Info: ╵
ID: フィールドが、DynamoDBに残っているロックIDです。このIDを使って手動でロックを解除します。2. force-unlockコマンドで安全に解除する
# 上記エラーのLock IDを指定して解除する terraform force-unlock a8f3c2d1-xxxx-xxxx-xxxx-7b9e43f1a2c4 # 確認プロンプトが出る。本当にロックされていないか確認してから yes を入力 Do you really want to force-unlock? Terraform will remove the lock on the remote state. This will allow local Terraform commands to modify this state, even though it may still be in use. Only 'yes' will be accepted to confirm. Enter a value: yes Terraform state has been successfully unlocked!
terraform apply を実行中の場合に使うと、同時実行による状態破損が起きます。「誰も実行していない」ことをチームに確認してから実行してください。CI/CD環境では、パイプラインジョブが死んでいることをCI管理画面で確認します。3. ロックを残さないCI/CDの設計パターン
CI/CDでTerraformを実行する場合、パイプラインのタイムアウトとプロセスキルによってロックが残りやすい構造になっています。以下の設計でリスクを下げられます。・タイムアウトを長めに設定する:大規模インフラ変更では30分を超えることがある。CI側のジョブタイムアウトをTerraformの想定実行時間より長くする
・ロック取得後の強制終了を防ぐ:シグナルトラップ(trap)でプロセス終了時に
terraform force-unlock を自動実行するスクリプトを用意する(ただし実行中の場合を除く)・DynamoDB TTLを設定する:DynamoDBのロックテーブルにTTL(例:24時間)を設定しておけば、異常終了したロックが自動削除されてオペレーターが気づかないまま放置される事態を防げる
これら3つの設計を事前に組み込んでおくことで、CI/CDパイプラインのロック詰まりによる作業停止リスクを大幅に下げられます。
Terraformマニュアルを無料で受け取る >>
ドリフト検出と修正(コンソール手動変更の影響を確認する)
「先週のterraform planではNo changesだったのに、今日実行したら差分が大量に出た」これはドリフトと呼ばれる状態です。AWSコンソールや他のツールがTerraform管理外でリソースを変更すると、tfstateと実際のリソースの状態が食い違います。
1. terraform plan -refresh-onlyで現状差分を把握する
terraform plan -refresh-only(Terraform 0.15.4以降)は、リソースの変更や追加を提案せず、「現在のAWSリソースの状態をtfstateに反映するとどうなるか」だけを表示します。$ terraform plan -refresh-only Terraform will perform the following actions: # aws_security_group.web_sg will be updated in-place ~ resource "aws_security_group" "web_sg" { ~ description = "managed by Terraform" -> "Temp change for test" id = "sg-0a1b2c3d4e5f67890" # (5 unchanged attributes hidden) } Plan: 0 to add, 0 to change, 0 to destroy. Changes to Outputs: 0 changes to Outputs. Note: This plan only includes refreshing the Terraform state (not making any changes to actual infrastructure).
2. ignore_changesで吸収するかimportで取り込むかを判断する
ドリフトが判明したら、2つの対処法のどちらかを選びます。・Terraform管理に戻す:コンソール変更を元に戻すか、Terraformコードを変更後のリソース状態に合わせてから
terraform apply する・ドリフトを許容する:コンソール側の変更を正として認めたい属性に
ignore_changes を設定して、Terraformが差分として検出しないようにする設定上の変更はコンソール変更を許容するということです。チーム全体でどちらの方針を採るか、インフラの「真実の情報源(Single Source of Truth)」をどこに置くかを明確にすることが重要です。
# コンソール変更の description を Terraform が変更しないよう ignore_changes で吸収する resource "aws_security_group" "web_sg" { name = "web-sg" description = "managed by Terraform" lifecycle { ignore_changes = [description] } }
よくあるplanエラーのパターンと解決策
1. 「Error: Cycle detected」依存関係の循環
リソースAがリソースBを参照し、リソースBもリソースAを参照するような循環依存が発生すると、このエラーが出ます。│ Error: Cycle: aws_security_group.app_sg, aws_security_group.db_sg
aws_security_group_rule リソースを使ってセキュリティグループルールを分離することで循環を解消できます。aws_security_group 内の ingress / egress ブロックを削除し、別リソースとして定義します。2. 「Error: Provider configuration not present」
バックエンド設定が見つからない場合や、terraform init が完了していない状態で plan を実行した場合に発生します。│ Error: Provider configuration not present │ │ To work with aws_instance.web its original provider configuration at │ provider["registry.terraform.io/hashicorp/aws"] is required, but it has been │ removed. This occurs when a provider configuration is removed while objects │ created by that provider still exist in the state.
terraform init を再実行します。CI/CD環境ではプロバイダープラグインがキャッシュされていない場合に頻発します。-reconfigure フラグを付けて強制的に再初期化することで解消できます。# バックエンド設定を含めて再初期化する terraform init -reconfigure
3. 「Error: creating resource already exists」リソース重複エラー
Terraformの管理外で手動作成されたリソースと同じ名前のリソースをTerraformで作ろうとした時に発生します。│ Error: creating S3 Bucket (my-app-config-bucket): BucketAlreadyExists: │ The requested bucket name is not available. │ status code: 409, request id: XXXXXXXXXXXX
terraform import) か、コード側のリソース名を変更して別名で作成します。Terraform 1.5以降では import ブロックをHCLに書いてplanの一部として実行できます。applyが途中で止まった時のリカバリ手順
terraform apply が途中でCTRL+Cや強制終了で止まった場合、Terraformは「途中まで適用した状態」をtfstateに書き込んでいます。この状態からの回復は次の手順で行います。1. 現在のtfstateを確認する
# 現在 Terraform が管理しているリソースの一覧を表示する terraform state list # S3バックエンドの場合、現在のtfstateをローカルにダウンロードしてバックアップ terraform state pull > /tmp/tfstate-backup-20260708-100711.json
2. Stateロックを確認・解除してから再実行する
applyが強制終了した場合、Stateロックが残っている可能性があります。前述のforce-unlock でロックを解除してから、terraform apply を再実行してください。Terraformは「tfstateにすでに存在するリソース」はスキップして「まだ適用されていないリソース」だけを処理します。途中から再開できる仕組みになっているため、通常は再実行で問題なく完了します。
3. 一部のリソースが壊れた状態になっていた場合
まれに、applyが途中で止まったことで「半壊」したリソースが残る場合があります(RDSのクラスター作成中に止まった等)。この場合は以下の手順を取ります。・
terraform state list で問題のリソースを特定する・AWSコンソールで当該リソースの実際の状態を確認する
・リソースが中途半端に作成されている場合、AWSコンソールで手動削除してから
terraform state rm でtfstateから除外する・その後
terraform apply で再作成する本記事のまとめ
Terraformのplan・applyエラー調査で使うコマンドと手順をまとめます。| 問題のパターン | 使うコマンド・設定 |
|---|---|
| エラーの原因が分からない | export TF_LOG=DEBUG |
| ログが多すぎてファイルに保存したい | export TF_LOG_PATH=/tmp/terraform-debug.log |
| Stateロックが残っている | terraform force-unlock <LOCK_ID> |
| コンソール変更との差分を確認したい | terraform plan -refresh-only |
| applyが途中で止まってしまった | force-unlock後にterraform applyを再実行 |
| planで循環依存エラーが出た | aws_security_group_ruleでルールを分離 |
| initが未完了またはキャッシュが壊れた | terraform init -reconfigure |
関連記事もあわせてご覧ください。
・Terraformのtfstate管理とS3バックエンド設定|チーム運用で壊さないための基礎
・Terraformのstate操作コマンド実践ガイド|state list・state mv・state rmで既存インフラを安全に管理する方法
・Terraformのlifecycleブロックで本番リソースを誤削除から守る方法
Terraformマニュアルを無料で受け取る >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら
- 前のページへ:Terraformのstate操作コマンド実践ガイド|state list・state mv・state rmで既存インフラを安全に管理する方法
- この記事の属するカテゴリ:Terraformへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。
登録無料・いつでも解除できます