"Invalid for_each argument" during import

Hi. I’m trying to apply Chaining fort_each pattern but still receive the error. Please my Terraform config below:

variable "public_subnet_cidr" {
  type = map(string)
  default = {
    "eu-west-1a" = "10.0.3.0/24",
    "eu-west-1b" = "10.0.4.0/24",
    "eu-west-1c" = "10.0.5.0/24",
  }
}

resource "aws_subnet" "public" {
  for_each = var.public_subnet_cidr

  vpc_id            = aws_vpc.default.id
  availability_zone = each.key
  cidr_block        = each.value

  tags = {...}
}

resource "aws_eip" "nat" {
  for_each = aws_subnet.public

 tags = {...}
}

resource "aws_nat_gateway" "default" {
  for_each = aws_subnet.public

  allocation_id = aws_eip.nat[each.key].id
  subnet_id     = each.value.id

  tags = {...}
}

This config leads to the error:

Error: Invalid for_each argument
│ 
│   on ***.tf line 49, in resource "aws_eip" "nat":
│   49:   for_each = aws_subnet.public
│     ├────────────────
│     │ aws_subnet.public will be known only after apply

Did I miss something? Is there any mistake in the configuration?

For a new question, it is better to start a new topic of your own, rather than tag on the end of one from months ago.

You have not provided the definition of your resource aws_subnet.public used in the problem for_each, so it is not possible for us to see the cause of the error.

For a new question, it is better to start a new topic of your own, rather than tag on the end of one from months ago.

Makes sense. Sorry for messing things up.

You have not provided the definition of your resource aws_subnet.public

I’m sorry again. I copy-pasted the wrong snippet. I should be public everywhere in the provided configuration. I’ve fixed the names in my previous comment.

I think, in simplifying your configuration in preparation to post it, you’ve simplified away the problem entirely.

When I execute terraform plan on this configuration derived from yours:

variable "public_subnet_cidr" {
  type = map(string)
  default = {
    "eu-west-1a" = "10.0.3.0/24",
    "eu-west-1b" = "10.0.4.0/24",
    "eu-west-1c" = "10.0.5.0/24",
  }
}

resource "aws_subnet" "public" {
  for_each = var.public_subnet_cidr

  vpc_id            = "placeholder"
  availability_zone = each.key
  cidr_block        = each.value
}

resource "aws_eip" "nat" {
  for_each = aws_subnet.public
}

Terraform successfully reports a plan.

Hm. Thats true. For these particular subnets, I’m able to plan the configuration. I get the error when I’m trying to import a resource to another module.
Does it make sense for you?

Ahhh…

The implementation of import is currently on a journey from pretty hacky to less hacky, with some distance still to go.

I am not an expert in this, but basically, from what I remember, the configuration isn’t quite processed in the normal way, such that all values are available in the way you might expect, when doing an import.

If @apparentlymart happens to see this conversation he might be able to explain this in less vague terms.

I reported this manifestation into the already existing issue about this sort of thing: terraform import fails with "Invalid for_each argument" · Issue #32146 · hashicorp/terraform · GitHub

I think the appropriate workaround is to replace every

with

and consequently replace each.value with aws_subnet.public[each.key] within those blocks.

Aha, that explains everything. I was thinking about exactly the same workaround, I guess there is no other way for the time being.
I’d appreciate any update or detailed info about the topic.
Thank you very much.

Indeed, terraform import is essentially a weird way to run terraform plan with some extra importing behaviors kinda weirdly shimmed in, which was done on the journey to config-driven import, which is now available in the 1.5 series.

If you can, I would suggest using the new approach to import instead. It’s integrated better into the other work Terraform needs to do in order to turn a configuration into a desired state.

This first release of new-style import does have some limitations that mean it’s not appropriate for all situations. For example, its requirement for the import ID to be static means it isn’t approved for situations where the same root module gets applied multiple times with different input variables. For those situations the old separate command is typically easier to use right now. But if you are just getting started and don’t already have a big configuration to adapt then I suspect the configuration-based approach will be smoother.