シナリオ
午前2時だと想像してください。本番環境のデータベースを t3.medium から m5.large にスケールさせるためにホットフィックスをプッシュしているところです。terraform.tfvars ファイルを新しいインスタンスサイズに更新し、保存して terraform plan を実行します。しかし、スムーズなロールアウトの代わりに、ターミナルには赤いテキストが大量に表示されます。
Error: Value for undeclared variable
The root module does not declare a variable named "instance_size" but a value was
assigned to it in terraform.tfvars. To declare variable "instance_size", place this
block in one of your .tf files:
variable "instance_size" {
type = string
}
Terraformは厳密に型定義されており、明示的な宣言が必要です。任意のキーと値のペアを渡せる動的言語とは異なり、Terraformは .tfvars ファイルや -var フラグ内のすべての値に対して、対応する variable ブロックを要求します。設計図(blueprint)がそのデータを想定していない場合、Terraformは処理を拒否します。
なぜTerraformはエラーを出すのか
初期化フェーズ中、Terraformはカレントディレクトリにあるすべての .tfvars ファイルを自動的に読み込みます。max_db_connections = 100 のようなキーが見つかると、対応する variable "max_db_connections" {} ブロックがないか .tf ファイルを即座にスキャンします。その定義が見つからない場合、スペルミスや孤立した設定データによってステートが汚染されるのを防ぐため、プロセスを停止します。
このエラーの主な原因は以下の通りです:
- ブロックの定義忘れ:
terraform.tfvarsで値を定義したが、variables.tfでのvariable宣言を忘れている。 - タイポ(打ち間違い): あるファイルでは
instane_typeと書き、別のファイルではinstance_typeと書いているような単純なミス。 - 大文字と小文字の区別: Terraformは
Database_Nameとdatabase_nameを完全に別のエンティティとして扱います。 - ルートモジュール vs 子モジュール: ルートの
.tfvarsファイルから子モジュールの変数を直接設定しようとしている(これはTerraformでは許可されていません)。
クイック解決策
デプロイを再開するには、エラーメッセージから変数名を特定します。次に、variables.tf ファイルまたはルートディレクトリ内の他の .tf ファイルに宣言ブロックを追加します。
# variables.tf
variable "instance_size" {
description = "EC2インスタンスタイプ(例:m5.large)"
type = string
}
このブロックを保存すると、Terraformは変数ファイルで割り当てられた値を認識し、プランを続行します。
クリーンな設定のためのベストプラクティス
変数の不一致で CI/CD パイプラインを停滞させないようにしましょう。コードの同期を保つために以下の戦略を活用してください。
1. 1対1のマッピングを維持する
.tfvars ファイルのすべてのエントリは、variables.tf に対となる宣言を持つ必要があります。設定を廃止する場合(例:サブネット数を10から20に変更するなど)、両方のファイルから未使用の変数を削除することを忘れないでください。デッドコードは監査時の混乱を招きます。
2. モジュールに変数を正しく渡す
ルートの terraform.tfvars から子モジュールに直接値を注入することはできません。代わりに、ルートで変数を宣言し、それをモジュールブロックに明示的に渡す必要があります。
# root/variables.tf
variable "app_port" { type = number }
# root/main.tf
module "web_server" {
source = "./modules/web"
port = var.app_port
}
3. 早期かつ頻繁にバリデーションを行う
ローカルのワークフローや pre-commit フックの一部として terraform validate を実行してください。このコマンドは高速です。クラウドプロバイダーへの確認やステートファイルの更新を必要とせず、数秒で未宣言の変数を検出します。
4. 環境変数を確認する
原因がファイルではない場合もあります。Terraformは TF_VAR_ という接頭辞が付いたシェル変数も探します。ターミナルや Jenkins エージェントで export TF_VAR_api_key="12345" が設定されている場合、Terraformはコード内に variable "api_key" {} ブロックがあることを想定します。
確認方法
ターゲットを絞ったプランを実行して修正を確認します。宣言が正しければ、赤いエラーテキストの代わりに標準的な実行プランが表示されます。
terraform plan -out=tfplan
修正が成功すると、「No changes」メッセージまたは予定されているインフラストラクチャの更新リストが表示されます。エラーが消えれば、割り当てと宣言がようやく同期されたことになります。
午前2時のトラブルシューターのためのまとめ
- エラーメッセージから変数名を取得する。
.tfファイル内でvariable "変数名"を検索する。- 見当たらない場合は、
variables.tfにブロックを追加する。 - タイポや、
大文字と小文字の不一致がないか確認する。 terraform validateを実行して修正を確認する。

