This error means Terraform tried to expand a for_each but could not, because the keys of the collection it was given depend on something that will not exist until apply time. A typical trigger is keying a map on an ID that another resource outputs, like a subnet ID or an ARN. Terraform needs the keys during planning to build stable resource addresses, so a key that is unknown at plan time is a hard stop.
Error: Invalid for_each argument
on main.tf line 21, in resource "aws_route53_record" "app":
21: for_each = { for s in aws_instance.web : s.id => s }
The "for_each" value depends on resource attributes that cannot be
determined until apply, so Terraform cannot predict how many instances
will be created. To work around this, use the -target argument to first
apply only the resources that the for_each depends on.
What this error means
Terraform builds a resource address for every element of a for_each, using the key as the index, for example aws_route53_record.app["web-1"]. Those addresses have to be known when Terraform draws the plan, so it can show you and later track each instance. When the keys are derived from a computed attribute such as .id or .arn, Terraform cannot know them until the upstream resource is actually created, so it cannot produce a stable plan and it refuses. The map values are allowed to be unknown; only the keys must be known.
Common causes
- Keying a map on
.id,.arn, or another attribute output by a resource that has not been created yet. - Using
for_eachover the result of a data source that itself depends on a resource created in the same run. - Building the collection with a
forexpression that pulls the key from a computed field. - A module output that passes through a computed ID and is then used as a
for_eachkey downstream. - Toggling resources with a count or flag that is itself unknown until apply.
How to fix it
Stabilize
- Read the error and find the exact
for_eachline it names. Look at where the keys come from. If any part of the key expression references a resource attribute rather than a variable, local, or literal, that is the problem.
terraform plan
Diagnose
-
Confirm which value is unknown. The key expression is the culprit, not the whole map. In the example above, the keys are
s.id, which is computed. The valuessare fine. -
Decide on a stable key you control. Names, keys you set in your own variables, or literal strings are all known at plan time. IDs and ARNs are not.
Fix
Key the map on a static value you define, and move the computed attribute into the value where unknown data is allowed. For the example, key on an instance name you set rather than the generated ID:
resource "aws_instance" "web" {
for_each = toset(["api", "worker", "cron"])
ami = var.ami_id
instance_type = "t3.micro"
tags = { Name = each.key }
}
resource "aws_route53_record" "app" {
for_each = aws_instance.web
zone_id = var.zone_id
name = "${each.key}.example.com"
type = "A"
ttl = 300
records = [each.value.private_ip]
}
Here the keys come from names you control, so they are known at plan time, and the computed private_ip sits in the value where it is allowed to be unknown.
If you cannot restructure right now and just need to unblock a deploy, apply the upstream resource first so its attributes become known, then run a normal plan:
terraform apply -target=aws_instance.web
terraform plan
Treat -target as a one time escape hatch. If the code still keys on computed values, the next clean run will fail the same way.
How to prevent it
- Key every
for_eachon values you define: variable names, local map keys, or literals, never computed IDs. - Put computed attributes in the map values, not the keys, since values may be unknown at plan time.
- Avoid chaining a
for_eachoff a data source that depends on resources created in the same apply. - When passing collections between modules, pass stable keys through, not generated IDs.
- Review new
for_eachblocks in code review for any reference to.id,.arn, or similar computed fields in the key position.
When to call a senior engineer
If restructuring the keys ripples through modules, forces resource addresses to change, and threatens to destroy and recreate live resources, the fix is no longer a one line change. Rekeying a for_each can move state addresses, and getting that wrong replaces infrastructure you meant to keep. Erzon engineers can rework the keying, plan the state moves with terraform state mv so nothing is destroyed, and keep your apply clean through the change.
Want a senior engineer to just fix it?
Paste this exact error into the form. A senior engineer replies within one business hour with what is likely wrong and a flat quote. Triage is free.
Book a fix