"for_each" supports maps and sets of strings, but you have provided a set containing type object

I don’t know why I’m getting this error because the local definition looks fine to me:

locals {
  triggers_list = distinct(flatten([
    for database in var.extra_trigger_database : [
      for collection in var.collections : {
        database   = "mydatabse_${database}"
        collection = collection
      }
    ]
  ]))
}

But if I try to use inside resource below on a foreach:

resource "mongodbatlas_event_trigger" "extra_triggers" {
  for_each                    = local.triggers_list
  project_id                  = var.project_id
  app_id                      = var.app_id
  ...
}

I get this error:

╷
│ Error: Invalid for_each set argument
│ 
│   on main.tf line 35, in resource "mongodbatlas_event_trigger" "extra_triggers":
│   35:   for_each                    = local.triggers_list
│     ├────────────────
│     │ local.triggers_list is list of object with 12 elements
│ 
│ The given "for_each" argument value is unsuitable: "for_each" supports maps
│ and sets of strings, but you have provided a set containing type object.

Hi @fouadroumieh,

As the message describes, in local.triggers_list you seem to have constructed a list of objects, shaped like this:

[
  {
    database   = "mydatabse_something1",
    collection = "something1"
  },
  {
    database   = "mydatabse_something2",
    collection = "something2"
  },
]

Passing this value through toset will create a set of objects, which is not either a map or a set of strings.

For this to work you’ll need to decide on a suitable unique string key to use to identify each element and then project the list into a map using those keys.

If both database and collection together uniquely identify a “trigger” then you could concatenate them together with a delimiter that will not appear inside either of those two strings. I’m not sure what a suitable delimiter would be but I’m going to use a colon below as an example; if either your database name or your collection name might contain a colon then you should use a different delimiter to avoid potential key collisions.

resource "mongodbatlas_event_trigger" "extra_triggers" {
  for_each = tomap({
    for t in local.triggers_list :
    "${t.database}:${t.collection}" => t
  })

  project_id = var.project_id
  app_id     = var.app_id
  ...
}

Assuming the silly placeholder values I used to show the structure of your value above, this would declare instances with keys like this:

  • mongodbatlas_event_trigger.extra_triggers["mydatabse_something1:something1"]
  • mongodbatlas_event_trigger.extra_triggers["mydatabse_something2:something2"]

Of course in your real example it’ll have different strings than “something1” and “something2”, but hopefully this helps connect these different parts together so you can see how it ought to behave with your real values.

1 Like

Thanks @apparentlymart for your prompt reply! it’s working after couple of hours hair pulling :grin: