Introduction

Terraform requires for_each keys to be known during planning. The error appears when a map or set is built from IDs, ARNs, or expressions that only become available after apply. The stable fix is to keep the keys static and move dynamic values into the object payload.

Symptoms

  • terraform plan fails with Invalid for_each argument
  • The error says Terraform cannot determine the full set of keys
  • The expression depends on IDs from resources created in the same run
  • Adding depends_on does not help because the keys are still unknown

Common Causes

  • A for_each map uses resource IDs as its keys
  • A toset(...) expression depends on apply-time values
  • Locals combine outputs that do not exist until apply
  • The configuration confuses identity with runtime attributes

Step-by-Step Fix

  1. 1.**Inspect the expression in terraform console**
  2. 2.Separate the unstable values from the stable identifiers before changing the resource block.
bash
terraform console
> local.targets
> keys(local.targets)
  1. 1.Replace dynamic keys with fixed names
  2. 2.Use logical names such as public-a and public-b, then store unknown IDs inside the values.

```hcl locals { subnet_targets = { public-a = { subnet_id = aws_subnet.public_a.id } public-b = { subnet_id = aws_subnet.public_b.id } } }

resource "aws_route_table_association" "this" { for_each = local.subnet_targets subnet_id = each.value.subnet_id route_table_id = aws_route_table.public.id } ```

  1. 1.**Avoid toset(...) when instance identity matters**
  2. 2.Sets force Terraform to derive identity from the values themselves. Use an explicit map instead.

```hcl resource "aws_security_group_rule" "ingress" { for_each = { app = 8080 admin = 8443 }

from_port = each.value to_port = each.value protocol = "tcp" type = "ingress" security_group_id = aws_security_group.app.id } ```

  1. 1.Run a fresh plan and confirm the instance addresses are stable
  2. 2.A good fix removes the graph error and produces deterministic addresses under for_each.
bash
terraform plan

Prevention

  • Design for_each maps around business identifiers, not provider-generated IDs
  • Prefer maps over sets when lifecycle stability matters
  • Use terraform console early during local refactors
  • Document expected keys for reusable modules