Fix Terraform 'Missing resource instance key' When Referencing a count Resource Without an Index

beginner๐Ÿ—๏ธ Terraform2026-07-22| Terraform >= 0.12, any cloud provider (AWS / GCP / Azure), macOS / Linux / Windows

Error Message

Error: Missing resource instance key: Because aws_instance.web has "count" set, its attributes must be accessed on specific instances.
#terraform#count#resource-reference#hcl#index

TL;DR

You're treating a count resource like a single object. It's a list. Add an index: aws_instance.web[0] for the first instance, aws_instance.web[count.index] inside another counted resource, or aws_instance.web[*].id to collect all IDs at once.

What triggers this error

The moment you add count to a resource block, Terraform converts it into an ordered list โ€” even when count = 1. Every reference to that resource must specify which instance you mean. Skip the index and you get:

Error: Missing resource instance key: Because aws_instance.web has "count" set, its attributes must be accessed on specific instances.

Here's the setup that triggers it:

resource "aws_instance" "web" {
  count         = 3
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
}

output "web_ip" {
  value = aws_instance.web.private_ip  # โ† ERROR: missing index
}

Fix approaches

1. Reference a specific index

Know exactly which instance you want? Pick it by zero-based index:

output "first_web_ip" {
  value = aws_instance.web[0].private_ip
}

Indices start at 0 โ€” the second instance is [1], the third is [2]. Simplest fix for most cases.

2. Use a splat expression to get all values

Need the same attribute from every instance? The splat operator [*] returns a list in one shot:

output "all_web_ips" {
  value = aws_instance.web[*].private_ip
}

Works in outputs, locals, and anywhere a list is valid. One caveat: don't use it where the argument expects a single string โ€” you'll get a type mismatch error instead.

3. Inside another resource โ€” use count.index

Both resources using count? Map them 1-to-1 with count.index:

resource "aws_eip" "web" {
  count    = 3
  instance = aws_instance.web[count.index].id
}

Each EIP gets paired with the web instance at the same position โ€” EIP 0 โ†’ web[0], EIP 1 โ†’ web[1], and so on.

4. Switch from count to for_each (recommended for anything non-trivial)

Index juggling getting messy? That's a signal to switch to for_each. String keys replace numeric indices โ€” cleaner to read, and safe when items are added or removed mid-list:

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 }
}

With plain count, deleting "web-b" shifts every index above it โ€” Terraform sees "web-c" as changed and plans a destroy/recreate. With for_each, each instance has a stable string key, so removing "web-b" only touches "web-b".

Edge case: count = 1 still needs an index

This one catches people off guard. Even count = 1 turns the resource into a list:

resource "aws_instance" "bastion" {
  count         = 1
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
}

# Still errors:
resource "aws_eip" "bastion" {
  instance = aws_instance.bastion.id   # ERROR
}

# Correct:
resource "aws_eip" "bastion" {
  instance = aws_instance.bastion[0].id
}

Common places this shows up

  • Outputs โ€” referencing resource.name.attribute directly instead of indexing
  • Dependent resource arguments โ€” passing an ID or ARN to a resource that depends on a counted one
  • Locals โ€” computing a derived value from a counted resource attribute
  • Module inputs โ€” passing a single-value variable that expects a string, not a list

Verify the fix

Two commands to confirm everything is wired up correctly. First, validate the syntax:

terraform validate
Success! The configuration is valid.

Then run the plan. The output block or dependent resource should show an actual value โ€” an IP address, an ID, an ARN โ€” with no errors:

terraform plan

If anything is unexpectedly marked for replacement, double-check which index you referenced.

Quick reference cheatsheet

  • resource.name[0] โ€” first instance
  • resource.name[count.index] โ€” current index, inside another counted resource
  • resource.name[*].attr โ€” all instances, returns a list
  • resource.name[length(resource.name) - 1] โ€” last instance
  • { for k, v in resource.name : k => v.attr } โ€” map over a for_each resource

Related Error Notes