How to fix Error: Missing resource instance key - Because resource has for_each set, its attributes must be accessed on specific instances in Terraform
The 'Missing resource instance key' error occurs when you try to access attributes of a resource that has for_each set without specifying which instance to access. Fix it by using specific instance keys like aws_instance.example[each.key].id or using a for expression in outputs.
Quick fix
Fixes Error: Missing resource instance key - Because resource has for_each set, its attributes must be accessed on specific instances
# WRONG - will cause error
resource "aws_security_group_rule" "example" {
source_security_group_id = aws_security_group.web_app.id
}
# CORRECT - specify the instance key
resource "aws_security_group_rule" "example" {
for_each = var.rules
source_security_group_id = aws_security_group.web_app[each.key].id
}- Use bracket notation to access specific instances
- Use a for expression to iterate in outputs
- Fix IAM policy resources using ARNs from for_each
- Use dynamic blocks for complex multi-resource references
# WRONG - will cause errorresource "aws_security_group_rule" "example" {source_security_group_id = aws_security_group.web_app.id}# CORRECT - specify the instance keyresource "aws_security_group_rule" "example" {for_each = var.rulessource_security_group_id = aws_security_group.web_app[each.key].id}Error: Missing resource instance key - Because resource has for_each set, its attributes must be accessed on specific instances
What this error means
This error occurs when Terraform tries to reference a resource that uses the `for_each` meta-argument without specifying which instance to access. When a resource is created with `for_each`, it becomes a map of instances rather than a single resource. Each instance is identified by a unique key from the `for_each` collection. Terraform cannot infer which specific instance you want to reference when you try to access a resource attribute directly. For example, if you have `aws_instance.web_app` with `for_each = var.instance_config`, you cannot access `aws_instance.web_app.id` because Terraform doesn't know which instance's ID you want. You must specify the key: `aws_instance.web_app["instance-1"].id` or iterate over all instances. This validation prevents ambiguous resource references that could lead to unpredictable behavior or unintended resource destruction when your configuration changes.
Typical symptoms
- Terraform validate or plan fails immediately with 'Missing resource instance key' error
- Error message specifies: 'Because resource has for_each set, its attributes must be accessed on specific instances'
- Occurs when referencing resource attributes in outputs, variables, or other resource arguments
- IAM policy JSON resources fail when using resource ARNs from for_each'd resources
- Error appears when trying to pass resource attributes to modules or other resources
- Works fine with count but breaks when switching to for_each
Common causes
- Directly accessing resource attributes without specifying the for_each key (e.g., aws_instance.web[*] instead of aws_instance.web[each.key])
- Using single-resource syntax when the resource is created with for_each (missing the bracket notation)
- Mixing count and for_each patterns or using count.index with for_each resources
- Attempting to use resource attributes in contexts that don't support iteration (like inline IAM policy resources)
- Referencing resources that recently changed from count to for_each without updating all references
- Not iterating over for_each resources when building collections or composite resources
How to fix "Error: Missing resource instance key - Because resource has for_each set, its attributes must be accessed on specific instances"
When accessing a resource created with for_each, always specify the key using bracket notation:
# WRONG - will cause error
resource "aws_security_group_rule" "example" {
source_security_group_id = aws_security_group.web_app.id
}
# CORRECT - specify the instance key
resource "aws_security_group_rule" "example" {
for_each = var.rules
source_security_group_id = aws_security_group.web_app[each.key].id
}The key each.key refers to the current key from the for_each iteration. You can also use specific string keys if accessing a different for_each resource:
value = aws_instance.web_app["production"].idWhen building outputs that reference multiple for_each instances, use a for expression to iterate over all instances:
# WRONG
output "instance_ids" {
value = aws_instance.web_app.id
}
# CORRECT - iterate using for expression
output "instance_ids" {
value = { for k, v in aws_instance.web_app : k => v.id }
}
# Or as a list
output "instance_ids" {
value = [for instance in aws_instance.web_app : instance.id]
}This creates an output that contains the IDs of all instances, properly referencing each one individually.
When building IAM policies that reference resources created with for_each, use a for expression:
# WRONG - causes error
resource "aws_iam_role_policy" "example" {
policy = jsonencode({
Statement = [{
Action = "s3:GetObject"
Resource = aws_s3_bucket.example.arn # ERROR if bucket uses for_each
}]
})
}
# CORRECT - iterate over instances
resource "aws_iam_role_policy" "example" {
for_each = var.bucket_configs
policy = jsonencode({
Statement = [{
Action = "s3:GetObject"
Resource = aws_s3_bucket.example[each.key].arn
}]
})
}
# Or use a dynamic block
resource "aws_iam_role_policy" "example" {
policy = jsonencode({
Statement = [{
Action = "s3:GetObject"
Resource = [for bucket in aws_s3_bucket.example : bucket.arn]
}]
})
}For more complex scenarios, use Terraform's dynamic block to generate resource configuration based on for_each instances:
resource "aws_security_group" "main" {
name = "main-sg"
dynamic "ingress" {
for_each = aws_network_interface.example
content {
from_port = 443
to_port = 443
protocol = "tcp"
security_groups = [ingress.value.security_groups]
}
}
}The dynamic block iterates over the for_each collection, making each instance available as ingress.value.
If you're migrating from count to for_each, ensure all references are updated:
# OLD (with count)
resource "aws_instance" "web_app" {
count = var.instance_count
# ...
}
output "ids" {
value = aws_instance.web_app[*].id # Works with count
}
# NEW (with for_each)
resource "aws_instance" "web_app" {
for_each = var.instance_map
# ...
}
output "ids" {
value = [for instance in aws_instance.web_app : instance.id] # Must use for expression
}The splat syntax ([*]) works with count, but for_each requires explicit for expressions.
Advanced notes
Difference between count and for_each:
With count, resources are indexed by position (0, 1, 2...) and stored as a list. With for_each, resources are indexed by a user-specified key and stored as a map. This means:
- count uses splat syntax: aws_instance.web[*].id
- for_each requires explicit iteration: [for instance in aws_instance.web : instance.id]
Changing resource counts or reordering items in a count list causes Terraform to recreate downstream resources. Using for_each with stable keys prevents this issue, making it the preferred approach for complex configurations.
When to use each.key vs each.value:
- each.key - The key from your for_each map (usually a string identifier)
- each.value - The complete value object from your for_each map (useful for passing entire configuration objects)
Most commonly, you'll use each.key to access sibling resources and each.value to access the current resource's configuration.
Frequently asked questions
- What does "Error: Missing resource instance key - Because resource has for_each s" mean?
- This error occurs when Terraform tries to reference a resource that uses the for_each meta-argument without specifying which instance to access. When a resource is created with for_each, it becomes a map of instances rather than a single resource. Each instance is identified by a unique key from the for_each collection.
- How do I fix "Error: Missing resource instance key - Because resource has for_each s"?
- The 'Missing resource instance key' error occurs when you try to access attributes of a resource that has for_each set without specifying which instance to access. Fix it by using specific instance keys like aws_instance.example[each.key].id or using a for expression in outputs.
- What causes "Error: Missing resource instance key - Because resource has for_each s"?
- Directly accessing resource attributes without specifying the for_each key (e.g., aws_instance.web[*] instead of aws_instance.web[each.key]) Using single-resource syntax when the resource is created with for_each (missing the bracket notation) Mixing count and for_each patterns or using count.index with for_each resources
- Is the "Error: Missing resource instance key - Because resource has for_each s" error serious?
- It is a medium-severity error โ more of a blocker than a risk. The steps above resolve it.