Variable type issues going from 0.14 to 0.15

When I tried to upgrade to 0.15 I encountered this issued on my created modules with variables types.

variable "service_names" {
  type = map(object({
    container_definitions = list(object({
      name         = string,
      image        = string,
      portMappings = list(any),
      environment  = list(any),
      mountPoints  = list(any),
      privileged   = bool,
      links        = list(any),
      dockerLabels = map(string)
    })),
    volumes = list(object({
      name      = string,
      host_path = string
    }))
    service_load_balancers = list(any)
  }))
}

Depending on how the module is used, when parameters like mountpoint for ex are empty, everything is fine, but when there is some other type of element, like a map inside, it start giving errors like:

The resolved value of variable “service_names” is not appropriate: element types must all match for conversion to list.

or more often

The given value is not suitable for child module variable “service_names” defined at …/…/module/aws/ecs/standard/variables.tf:9,1-25: attribute types must all match for conversion to map.

For the second one, the same message comes for lists too.

I found a workaround for some of my modules, changing my list(any) into any, which is not amazing but this made me lose a lot of time and gave me headache.

But then, working with another old module, this came again, but now it seems that it’s the whole map (the larger one) that’s the issue. And I don’t get why as my modules are having the same structures.

The behavior when changing those type feels pretty odd, and I could definitely use some help as I cannot define why this no longer works as it did. As it was not specified in the upgrade guide.

Hi @GLimantour,

The type declaration for the variable is a type constraint, meaning that any value of that variable must satisfy that type. Because of the use of any within the type constraint, multiple values which satisfy the type may not be of the same type themselves, and may not be usable in the same context.

Starting at the innermost level, the type list(any) means “a list of any single type”, which could be satisfied by list(string), or list(map(string)), list(list(number)), etc., but none of those types are interchangeable. As you move outward, you can see that values which satisfy container_definitions and service_names could have very different types, as the maps and lists must have homogeneous types themselves.

Hopefully this helps clarify things a bit for you. If you have a specific case in mind, we would need an example to try and provide more guidance. In general, if you can specify the exact type needed, you are less likely to get into situations where an unexpected value causes hard to diagnose failures later on.