Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Infrastructure as Code By James Joyner IV · · 9 min read

OpenTofu Error Guide: 'Invalid for_each argument' — Fix Unknown Keys at Plan Time

Quick answer

Fix OpenTofu 'Invalid for_each argument' by giving for_each statically-known keys, staging applies with -target, or restructuring computed dependencies.

  • #iac
  • #infrastructure-as-code
  • #troubleshooting
  • #errors
Free toolkit

Fixing errors like this? Get 500 free DevOps AI prompts

500 copy-paste AI prompts for the stack you actually run — one PDF, free.

Overview

OpenTofu must know the full set of instance keys a for_each will create at plan time, because those keys become part of each resource’s address in state. When the keys depend on a value that is only known after another resource is applied, the plan cannot be built and OpenTofu errors:

Error: Invalid for_each argument

  on main.tf line 22, in resource "aws_route53_record" "this":
  22:   for_each = { for r in aws_instance.web : r.private_ip => r }

The "for_each" map includes keys derived from resource attributes that cannot be
determined until apply, and so OpenTofu cannot determine the full set of keys
that will identify the instances of this resource.

Symptoms

  • tofu plan fails with Invalid for_each argument and a note that keys “cannot be determined until apply.”
  • The for_each expression references attributes of another resource (IDs, IPs, ARNs) computed on apply.
  • The config planned fine before you switched the source to a resource-derived collection.
  • A related message: The given "for_each" argument value is unsuitable: the given "for_each" argument value is null or contains unknown values.

Common Root Causes

  • Keys derived from computed attributesfor_each over a map whose keys come from aws_instance.*.private_ip, an ARN, or any post-apply value.
  • for_each over a resource that does not exist yet in the same apply.
  • Data source not yet readable at plan — a data block that depends on a resource created in the same run.
  • Unknown-length collectionsfor_each on the result of a function fed unknown values.
  • Conflating values and keys — it is fine for map values to be unknown, but keys must be known at plan.

Diagnostic Workflow

Reproduce and read which expression feeds for_each:

tofu plan 2>&1 | sed -n '1,25p'

Inspect the resource and what its for_each depends on:

grep -nA4 "for_each" main.tf

Check whether the source attribute is computed (known only after apply) by looking at the dependency:

tofu graph | grep -i "aws_instance.web"

Confirm the keys are the problem, not the values — try keying on a static input instead:

# static keys from a variable = known at plan; values may stay computed
grep -nA4 "variable \"names\"" variables.tf

Example Root Cause Analysis

An engineer wanted a DNS record per web instance:

resource "aws_route53_record" "this" {
  for_each = { for r in aws_instance.web : r.private_ip => r }
  # ...
}

tofu plan failed with Invalid for_each argument because r.private_ip is assigned by AWS at apply time, so the keys of the map were unknown at plan — OpenTofu could not determine how many records to create or their addresses.

The fix was to key the map on something known at plan time. The instances themselves were created with a static for_each over a variable of names, so each instance already had a known key. Re-expressing the records to key on that same static name (for k, inst in aws_instance.web : k => inst) made the record keys plan-known, while the value (inst.private_ip) stayed computed and resolved at apply — which is allowed. Where truly no static key existed, the alternative was a staged apply: tofu apply -target=aws_instance.web first, then a normal apply so the IPs were known before the records planned.

Prevention Best Practices

  • Key for_each on values known at plan time (input variables, static locals), never on computed resource attributes.
  • It is fine for map values to be unknown at plan — only the keys must be known; restructure so keys come from static inputs.
  • When keys genuinely depend on apply-time data, split into stages with -target, or move the dependency into a separate apply.
  • Prefer deriving both instances and their dependents from the same static source so their keys line up.
  • Avoid count with unstable ordering as a workaround; it causes churn on list changes.

Quick Command Reference

tofu plan                                     # reproduce the error
grep -nA4 "for_each" *.tf                      # find the offending expression
tofu graph | grep <resource>                   # see the dependency edge
tofu apply -target=aws_instance.web            # staged apply to resolve keys
tofu plan                                      # re-plan with keys now known

Conclusion

Invalid for_each argument means the keys of your for_each are computed and thus unknown at plan time, so OpenTofu cannot address the instances it would create. The durable fix is to key on statically-known inputs (variables or locals) and let only the values stay computed. When a dependency truly forces apply-time keys, stage the apply with -target so the keys are known before the dependent resource plans.

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.