TL;DR
count リソースを単一オブジェクトとして扱っています。これはリストです。インデックスを追加してください: 最初のインスタンスには aws_instance.web[0]、別のカウントリソース内では aws_instance.web[count.index]、すべてのIDを一度に収集するには aws_instance.web[*].id を使います。
このエラーが発生する原因
リソースブロックに count を追加した瞬間、Terraformはそれを順序付きリストに変換します — count = 1 の場合でも同様です。そのリソースへのすべての参照で、どのインスタンスを指すかを指定する必要があります。インデックスを省略すると次のエラーが発生します:
Error: Missing resource instance key: Because aws_instance.web has "count" set, its attributes must be accessed on specific instances.
このエラーを引き起こす設定例:
resource "aws_instance" "web" {
count = 3
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
}
output "web_ip" {
value = aws_instance.web.private_ip # ← エラー: インデックスが欠落
}
修正方法
1. 特定のインデックスを参照する
どのインスタンスが必要かわかっている場合は、0始まりのインデックスで指定します:
output "first_web_ip" {
value = aws_instance.web[0].private_ip
}
インデックスは0から始まります — 2番目のインスタンスは [1]、3番目は [2] です。ほとんどのケースで最もシンプルな修正方法です。
2. スプラット式を使ってすべての値を取得する
すべてのインスタンスから同じ属性が必要な場合は、スプラット演算子 [*] を使うと一度にリストで返されます:
output "all_web_ips" {
value = aws_instance.web[*].private_ip
}
アウトプット、ローカル変数、リストが有効な場所であればどこでも使えます。ただし注意点があります: 引数が単一の文字列を期待する場所では使わないでください — 型の不一致エラーが発生します。
3. 別リソース内での参照 — count.index を使う
両方のリソースが count を使っている場合は、count.index で1対1にマッピングします:
resource "aws_eip" "web" {
count = 3
instance = aws_instance.web[count.index].id
}
各EIPは同じ位置のwebインスタンスとペアになります — EIP 0 → web[0]、EIP 1 → web[1]、という具合です。
4. count から for_each に切り替える(複雑な場合に推奨)
インデックスの管理が煩雑になってきた場合は、for_each に切り替えるサインです。数値インデックスの代わりに文字列キーを使います — 読みやすく、リストの途中でアイテムが追加・削除されても安全です:
variable "web_names" {
default = ["web-a", "web-b", "web-c"]
}
resource "aws_instance" "web" {
for_each = toset(var.web_names)
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
tags = {
Name = each.key
}
}
output "web_ips" {
value = { for k, v in aws_instance.web : k => v.private_ip }
}
通常の count では、"web-b" を削除するとそれ以降のインデックスがすべてずれます — Terraformは "web-c" が変更されたと判断し、削除と再作成を計画します。for_each では各インスタンスが安定した文字列キーを持つため、"web-b" を削除しても "web-b" だけに影響します。
エッジケース: count = 1 でもインデックスが必要
これは多くの人が気づかないポイントです。count = 1 でもリソースはリストになります:
resource "aws_instance" "bastion" {
count = 1
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
}
# これはエラーになります:
resource "aws_eip" "bastion" {
instance = aws_instance.bastion.id # ERROR
}
# 正しい書き方:
resource "aws_eip" "bastion" {
instance = aws_instance.bastion[0].id
}
よく発生する箇所
- アウトプット — インデックスなしで
resource.name.attributeを直接参照している場合 - 依存リソースの引数 — カウントリソースに依存するリソースにIDやARNを渡す場合
- ローカル変数 — カウントリソースの属性から派生値を計算する場合
- モジュールの入力 — リストではなく文字列を期待する変数に単一の値を渡す場合
修正の確認方法
すべてが正しく設定されているか確認するための2つのコマンドです。まず構文を検証します:
terraform validate
Success! The configuration is valid.
次にプランを実行します。アウトプットブロックや依存リソースには、エラーなしで実際の値 — IPアドレス、ID、ARN — が表示されるはずです:
terraform plan
予期せず置き換えとしてマークされているものがあれば、参照しているインデックスを再確認してください。
クイックリファレンスチートシート
resource.name[0]— 最初のインスタンスresource.name[count.index]— 現在のインデックス(別のカウントリソース内で使用)resource.name[*].attr— すべてのインスタンス(リストを返す)resource.name[length(resource.name) - 1]— 最後のインスタンス{ for k, v in resource.name : k => v.attr }—for_eachリソースをマップ処理する

