How to fix Error: Invalid for_each value - for_each value must be a set in Terraform

TerraformINTERMEDIATEMEDIUMUpdated Dec 31, 2025ยท 136 views

Terraform's for_each meta-argument requires a set or map, not a list. Learn how to convert lists to sets and fix this common configuration error.

Quick fix

Fixes Error: Invalid for_each value - for_each value must be a set

variable "instance_names" {
  type = list(string)
  default = ["web-server", "app-server", "db-server"]
}

resource "aws_instance" "example" {
  for_each = toset(var.instance_names)

  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  tags = {
    Name = each.value
  }
}
  1. Convert lists to sets using toset()
  2. Use for expressions to convert lists of objects to maps
  3. Verify your data source outputs a set or map
  4. Declare variables with correct types from the start
terraform โ€” error
variable "instance_names" {
type = list(string)
default = ["web-server", "app-server", "db-server"]
}
resource "aws_instance" "example" {
for_each = toset(var.instance_names)
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = each.value
}
}
Error: Invalid for_each value - for_each value must be a set

What this error means

The for_each meta-argument in Terraform is used to create multiple instances of a resource based on a collection of values. However, for_each has strict type requirements: it only accepts sets (set(string)) or maps. When you attempt to use a list, tuple, or other unsupported data type with for_each, Terraform returns this error because it cannot iterate over the value in the expected way. The error occurs at configuration validation time, before any resources are created. This is a configuration syntax issue, not a runtime problem. The solution involves converting your data to the correct type using Terraform functions like toset() or by restructuring your data using for expressions.

Typical symptoms

  • Terraform returns 'Invalid for_each value' error when running plan or apply
  • Error message specifically mentions for_each requires a set or map
  • Configuration fails validation even though your values look correct
  • Error occurs when passing a list variable to for_each
  • Using outputs or data source attributes with for_each causes validation failure

Common causes

  1. Using a list (list(string)) with for_each instead of a set (set(string))
  2. Attempting to iterate over a list directly without converting it to a set
  3. Passing a tuple or other unsupported collection type to for_each
  4. Using dynamic values from data sources or computed attributes that don't result in a set or map
  5. Attempting to use for_each with a string value instead of a collection

How to fix "Error: Invalid for_each value - for_each value must be a set"

1Convert lists to sets using toset()

If you have a variable declared as list(string), wrap it with the toset() function when passing it to for_each:

hcl
variable "instance_names" {
  type = list(string)
  default = ["web-server", "app-server", "db-server"]
}

resource "aws_instance" "example" {
  for_each = toset(var.instance_names)

  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  tags = {
    Name = each.value
  }
}

The toset() function converts your list into a set, which for_each requires. Each element becomes accessible via each.value.

2Use for expressions to convert lists of objects to maps

When working with complex data structures like lists of objects, use a for expression to create a map:

hcl
variable "instances" {
  type = list(object({
    name = string
    type = string
  }))
  default = [
    { name = "web", type = "t2.micro" },
    { name = "app", type = "t2.small" }
  ]
}

resource "aws_instance" "example" {
  for_each = { for item in var.instances : item.name => item }

  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = each.value.type

  tags = {
    Name = each.key
  }
}

This creates a map where keys are instance names and values are the full objects. Access properties via each.value.property.

3Verify your data source outputs a set or map

When using data sources or locals to populate for_each, ensure the output is a set or map. If it's a list, apply toset():

hcl
data "aws_availability_zones" "available" {
  state = "available"
}

# This will fail - aws_availability_zones returns a list
# resource "aws_subnet" "example" {
#   for_each = data.aws_availability_zones.available.names  # ERROR!
# }

# Correct - wrap with toset()
resource "aws_subnet" "example" {
  for_each = toset(data.aws_availability_zones.available.names)

  vpc_id              = aws_vpc.main.id
  cidr_block          = "10.0.${index(tolist(each.value), each.key)}.0/24"
  availability_zone   = each.value
}
4Declare variables with correct types from the start

The best approach is to declare your variables with the correct type annotation:

hcl
# Use set(string) for collections of strings
variable "environment_names" {
  type = set(string)
  default = ["dev", "staging", "prod"]
}

# Use map() for key-value data
variable "resource_tags" {
  type = map(string)
  default = {
    environment = "production"
    team        = "platform"
  }
}

# Now for_each works directly without conversion
resource "aws_instance" "by_env" {
  for_each = var.environment_names
  # ...
}

resource "aws_s3_bucket_tag" "tags" {
  for_each = var.resource_tags
  # ...
}
5Check for computed or dynamic values

If for_each depends on computed values that aren't known until apply time, restructure your configuration. Terraform requires for_each values to be known during the plan phase:

hcl
# Problem: Using outputs that depend on created resources
# for_each = aws_instance.created[*].id  # ERROR - can't predict count until apply

# Solution: Define keys statically, put apply-time values in map values
resource "aws_instance" "servers" {
  for_each = {
    "server1" = {}
    "server2" = {}
  }
  # ...
}

resource "aws_eip" "servers" {
  for_each = aws_instance.servers
  instance = each.value.id
}

Keep the iteration keys static and place computed values in the map values instead.

6Run terraform validate to confirm the fix

After making your changes, validate your configuration:

bash
terraform validate

If successful, you'll see: "Success! The configuration is valid."

Then run plan to see what Terraform intends to create:

bash
terraform plan

The error should now be resolved, and you can proceed with apply.

Advanced notes

When working with sensitive values, you cannot use them directly in for_each because Terraform cannot predict the for_each value during planning. To work around this, split sensitive values from keys: declare keys as a static set/map, and reference sensitive values only in the map values.

For resource attributes that can't be determined until apply time, restructure to keep iteration keys static (defined directly in your config) and place the computed values in the map values instead. This allows Terraform to predict the for_each behavior during planning.

On older Terraform versions (pre-0.12), for_each was not available; use count with index() instead, though for_each is preferred in modern configurations.

Frequently asked questions

What does "Error: Invalid for_each value - for_each value must be a set" mean?
The for_each meta-argument in Terraform is used to create multiple instances of a resource based on a collection of values. However, for_each has strict type requirements: it only accepts sets (set(string)) or maps. When you attempt to use a list, tuple, or other unsupported data type with for_each, Terraform returns this error because it cannot iterate over the value in the expected way.
How do I fix "Error: Invalid for_each value - for_each value must be a set"?
Terraform's for_each meta-argument requires a set or map, not a list. Learn how to convert lists to sets and fix this common configuration error.
What causes "Error: Invalid for_each value - for_each value must be a set"?
Using a list (list(string)) with for_each instead of a set (set(string)) Attempting to iterate over a list directly without converting it to a set Passing a tuple or other unsupported collection type to for_each
Is the "Error: Invalid for_each value - for_each value must be a set" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading