Tags Merge : Call to function "merge" failed: arguments must be maps or objects, got "tuple"

Hi all,
I want to merge local tags in azuread resource in terraform 0.12.17
I try to format the tags in azuread format (differ from azurerm)

i have this

locals {
timestamp = “${timestamp()}”

ad_mandatory_tags = [
map( “app_code” , “var.app_code”,
“app_label” , “var.app_label”,
“app_owner” , “var.app_owner”,
“asset” , “var.asset”,
“environment” , “var.environment”,
“app_criticity” , “var.app_criticity”,
“app_security_level” , “var.app_security_level”,
“auto_shutdown_schedule” , “var.auto_shutdown_schedule”)
]

ad_extra_tags = [
map(“terraform” , “var.terraform”)
]
}

resource “azuread_application” “default” {
name = var.app_registration_name
homepage = var.homepage
available_to_other_tenants = false
oauth2_allow_implicit_flow = true
}

resource “azuread_service_principal” “default” {
application_id = azuread_application.default.application_id

tags = merge(local.ad_mandatory_tags, local.ad_extra_tags)
}

MESSAGE ERROR
Error: Invalid index

on service_principal.tf line 15, in resource “azuread_service_principal” “default”:
15: tags = merge(local.ad_mandatory_tags[0], local.ad_extra_tags[1])
|----------------
| local.ad_extra_tags is tuple with 1 element

The given key does not identify an element in this collection value.

Have you a idea to help me ?

Your local.ad_extra_tags is defined like this:

  ad_extra_tags = [
    map(“terraform” , “var.terraform”)
  ]

The above creates a tuple with a single element, whose index is 0. Therefore it’s invalid to refer to index 1: there is no such element, and so Terraform returns this error.

The map function returns a map, and then the [ ... ] brackets wrap that in a tuple. If you wanted just a map, as seems to be the case here, then you don’t need those brackets.

Note also that the map function exists only for backward-compatibility with Terraform 0.12 and should not be used in new code. Use { ... } brackets instead.

  ad_extra_tags = {
    terraform = var.terraform
  }

I also unquoted the "var.terraform" here because I’m assuming you intended to refer to a variable called terraform, not to use var.terraform as a literal string. If so, that applies to all of your other references here too.

If you remove these tuple brackets around your expressions then your merge call will simplify as follows:

  tags = merge(local.ad_mandatory_tags, local.ad_extra_tags)

Thanks for your reply, but this is what i do excatly before for all my code using azurerm provider :slight_smile:

But this doesn’t work with azuread module such as azuread_service_principal for example !
Tags syntax is different in azuread resource.

If i use your code method i have this error message (using my other locals for azurerm tags)

Error: Incorrect attribute value type

on service_principal.tf line 15, in resource “azuread_service_principal” “default”:
15: tags = merge(local.mandatory_tags, local.extra_tags)

Inappropriate value for attribute “tags”: set of string required.

Hi @Kumoservices,

I’m afraid I’m not very knowledgeable about Azure in particular, so I’m not sure exactly what data structure is required for tags. Can you show an example of what this would look like if you were writing out the tags argument directly as a constant value, rather than as a function call? Then hopefully I can show how to generate an equivalent result dynamically using Terraform expressions.

hi martin,

Sure,

Terraform doc example

Git hub source

resource "azuread_service_principal" "example" {
  application_id               = "${azuread_application.example.application_id}"
  app_role_assignment_required = false

  **tags = ["example", "tags", "here"]**
}

Thanks @Kumoservices.

So it looks like tags is a set of strings for this resource. Given that, I’m not sure how to interpret the examples you gave in your original question where you seemed to be using lists of maps to build the tags value, rather than lists of strings.

Could you write an example that uses the actual values you want to use in your configuration, rather than the generic ones shown in the documentation? That way I can better understand how the local values you defined in the example you showed earlier correspond to the result you want to achieve.

I want to put my tag “key = value”

with my locals.tf

locals {
  timestamp = "${timestamp()}"

  mandatory_tags = {
    app_code               = var.app_code
    app_label              = var.app_label
    app_owner              = var.app_owner
    asset                  = var.asset
    environment            = var.environment
    app_criticity          = var.app_criticity
    app_security_level     = var.app_security_level
    auto_shutdown_schedule = var.auto_shutdown_schedule
  }

  extra_tags = {
    terraform          = var.terraform
  }
}

resource "azurerm_key_vault_secret" "default" {
  name         = "${var.app_code}-${var.environment}-serviceprincipal-password"
  value        = sha256(bcrypt(random_string.default.result))
  key_vault_id = azurerm_key_vault.default.id

  # ignoring the changes in the secret for new terraform executions
  lifecycle {
    ignore_changes = [value]
  }

  tags = merge(local.mandatory_tags, local.extra_tags)

}

I want tag my azuread_service_principal resource with mandatory_tags and extra_tags with the merge.

maybe i make a mistake and it is not possile to tags this resource with key value ? but that will be seems stange to me.

@Kumoservices,

Please write a tags argument that does not call any functions at all and only includes constant values. That is how I can understand the result you want, not the approach you’re trying to take to get there. I can’t help you if you don’t show me exactly what tag values – constant strings, not a function call – you want your object to have.