エラーのシナリオあるリソースが別のリソースの出力に依存するようなインフラを構築しているとします。例えば、一連のサブネットを作成し、作成された各サブネットに対してEC2インスタンスを起動しようとする場合です。コードの論理は正しく見えますが、terraform planを実行すると、次のような壁にぶつかります。
Error: Invalid count argument
on main.tf line 24, in resource "aws_instance" "web":
24: count = length(aws_subnet.public_subnets[*].id)
The "count" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will be created.
発生原因Terraformは明確に分かれたフェーズで動作します。Planフェーズでは、Terraformは依存関係グラフを構築し、作成、更新、または削除が必要なリソースの数を正確に計算します。これを行うには、countまたはfor_eachに渡されるすべての値が、実際にインフラが操作される前に確定している必要があります。
このエラーは、リソース作成後にのみ存在する属性(生成されたID、計算されたARN、まだ存在しないリソースからのIDリストなど)をcountに指定したときに発生します。applyが完了するまで何個のIDが返されるかTerraformは予測できないため、処理を拒否します。
解決方法構成に応じて、いくつかの対処法があります。ここでは最も効果的な戦略を紹介します。
1. 変数やLocalsからロジックを制御する(推奨)countをリソースの出力(output)に依存させるのではなく、そのリソースを定義する入力(input)に依存させます。CIDRブロックのリストに基づいてサブネットを作成している場合は、その同じリストを使用してインスタンスの数を決定します。
誤った方法:
resource "aws_subnet" "example" {
count = 3
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index}.0/24"
}
resource "aws_instance" "server" {
# エラー: サブネットが作成されるまでIDは不明
count = length(aws_subnet.example[*].id)
ami = "ami-123456"
instance_type = "t3.micro"
}
正しい方法:
locals {
subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
}
resource "aws_subnet" "example" {
for_each = toset(local.subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = each.value
}
resource "aws_instance" "server" {
# 成功: local.subnet_cidrsはPlan時に確定している
for_each = toset(local.subnet_cidrs)
ami = "ami-123456"
instance_type = "t3.micro"
subnet_id = aws_subnet.example[each.value].id
}
2. フィルター付きのデータソースを使用する既存のリソースや別のステートファイルで管理されているリソースをカウントする場合は、フィルター付きのdataソースを使用します。フィルターが静的な文字列であれば、Terraformは多くの場合Planフェーズでデータソースを解決できます。
data "aws_subnets" "existing" {
filter {
name = "vpc-id"
values = [var.vpc_id]
}
}
resource "aws_instance" "worker" {
count = length(data.aws_subnets.existing.ids)
ami = "ami-xxxxxx"
instance_type = "t2.micro"
}
3. 「2段階」のApply(暫定的な修正)すぐにコードをリファクタリングできない緊急の場合は、まず依存先のリソースをターゲットにして、Terraformに属性を認識させることができます。これは手動の回避策であり、CI/CDパイプラインにおける長期的な解決策ではありません。
terraform apply -target=aws_subnet.exampleを実行します。- サブネットが存在し、そのIDがステートファイルに保存されたら、通常の
terraform applyを実行します。 IDがステートに保存されたことで、Terraformは2回目の実行のPlanフェーズでlength()を解決できるようになります。
動作確認修正が機能したことを確認するには、Planを実行し、出力されるリソース数を確認します。
terraform plan
修正が成功していれば、「depends on resource attributes」エラーの代わりに、計画されたリソースの明確なリスト(例:Plan: 5 to add, 0 to change, 0 to destroy)が表示されます。for_eachを使用している場合は、Plan出力のキーが (known after apply) ではなく、期待される静的な識別子(CIDRブロックや名前など)と一致していることを確認してください。
予防策
- 静的なキー:
for_eachのキーには、データベースIDや生成されたUIDではなく、常に静的な文字列(名前、CIDR、タグなど)を使用してください。 count = length(data.something.ids)を避ける: そのデータソースが同じワークスペース内で作成されたリソースに依存している場合、失敗する可能性が高いです。- 入力主導の設計: リソース数の「信頼できる情報源(Source of Truth)」が常に変数やLocalsの定数になるようにモジュールを構成してください。

