I’m currently facing an issue in my Terraform configuration, specifically with the "Invalid for_each argument" error. I have a configuration that involves creating AWS Load Balancer target groups and attachments. I’m using a local.c variable with keys derived from resource attributes, and it seems that Terraform is unable to determine the full set of keys during the planning phase.
As I am a new to Terraform. Please help me with this problem. What will be the better solution?
This is my main.tf an variables.tf
resource "aws_lb_target_group" "tg" {
# count = length(var.target-port)
# name = "${var.targetgroup-name}-${var.target-port[count.index]}"
# port = var.target-port[count.index]
for_each = toset(var.target-port)
name = "${var.targetgroup-name}-${each.value}"
port = each.value
protocol = "HTTP"
vpc_id = "vpc-571f3830"
}
locals {
a = {for anr in aws_lb_target_group.tg : anr.arn => anr}
}
locals {
b = {for p in setproduct(var.target, var.target-port):
"${p[0]}-${p[1]}" => p}
}
locals {
c = {for c in setproduct(local.a, local.b):
"${c[0]}-${c[1]}" => c}
}
resource "aws_lb_target_group_attachment" "tg-attach" {
for_each = local.c
target_group_arn = each.value[0]
target_id = each.value[1]
port = each.value[2]
depends_on = [ aws_lb_target_group.tg]
}
variables.tf
variable "target-port" {
type = set(string)
default = [ "81" , "82" , "83" , "84" , "85" ]
}
variable "listenerport" {
type = set(string)
default = [ "81" , "82" , "83" , "84" , "85" ]
}
variable "target" {
type = set(string)
default = ["i-08990bdd2df0" , "i-0d3b9802d7ac"]
}
variable "targetgroup-name" {
default = "terraform-alb-tg"
}
The error I faced was
Error: Invalid for_each argument
│
│ on main.tf line 47, in resource "aws_lb_target_group_attachment" "tg-attach":
│ 47: for_each = local.c
│ ├────────────────
│ │ local.c will be known only after apply
│
│ The "for_each" map includes keys derived from resource attributes that cannot be determined until apply, and so
│ Terraform cannot determine the full set of keys that will identify the instances of this resource.
│
│ When working with unknown values in for_each, it's better to define the map keys statically in your configuration
│ and place apply-time results only in the map values.
│
│ Alternatively, you could use the -target planning option to first apply only the resources that the for_each value
│ depends on, and then apply a second time to fully converge.
The result I need is simple. I want to create Targetgroups with these ports and attachment will be these 2 ec2 instances id.
2
Answers
The error is clear,
local.c
will be known after apply, which is forbidden in TF when creating resources usingfor_each
orcount
. You must ensure that all your local variables are known atplan
time.You have to deploy your resources in two stages., First the resources that are used for
local.c
, and then everything else then depends on those resource.The error message has more details giving clues on how to solve the problem too..
-target
option helps you create independent resources in the first go & followed by dependent resources. Doesn’t scale well with CI/CD as you can’t expect all the resources you are going to create with two-pronged approaches.When working with unknown values in for_each, it's better to define the map keys statically in your configuration │ and place apply-time results only in the map values.
The 2nd approach is what I use heavily. But you have to redesign your
tf
configuration files accordingly with deterministic names (not usingrandom
ones).In your case, rather relying directly on
aws_lb_target_group.tg
output you predict the output would be something like a staticarn:aws:elasticloadbalancing:us-west-2:187416307283:targetgroup/app-front-end/20cfe21448b66314
. With this, you could construct yourlocal
variables& use in dependent resources with
depends_on
meta-argument (it is a must otherwise you hit race conditions).If you would like to know more about this constraint, read this comment.