Understanding error - "element types must all match for conversion to list"

Hi,

I came across this issue yesterday when supplying a map of objects as a variable to a module and even after I “fixed” it, it wasn’t obvious to me why I was seeing this behaviour. Here’s an example of what my configuration looked like:

Code calling the module:

locals {
  dashboards = {
    app_service_plans = var.app_service_plans_dashboard
  }
}

module "grafana_dashboards" {
  source                      = "../../modules/grafana_dashboard"
  for_each                    = local.dashboards 
  environment                 = var.env
  dashboard_folder            = each.value.folder
  dashboard_title             = each.value.title
  dashboard_json_model        = each.value.template_json
  dashboard_panels            = each.value.panels
}

var.app_service_plans_dashboard definition:

variable "app_service_plans_dashboard" {
  type = object({
    title         = string
    folder        = string
    template_json = string
    panels = list(object({
      title             = string
      type              = string
      metric            = string
      metric_namespace  = string
      alerts = optional(map(object({
        enabled              = optional(bool, false)
        pause_evaluation     = optional(bool, false)
        aggregation          = optional(string, "Average")
        threshold            = optional(number)
        interval_ms          = optional(number, 60000)
        reduction_expression = optional(string, "last")
        eval_operator        = optional(string)
        pending_period       = optional(string, "5m")
        contact_point        = optional(string)
        time_range           = optional(number, 21600)
      })), {})
    }))
  })
  default = null
}

var.app_service_plans_dashboard value in tfvars:

app_service_plans_dashboard = {
  title         = "OCPP App Service Plans (Dev)"
  folder        = "OCPP Dev"
  template_json = "./templates/generic-grafana-dashboard.tftpl"
  panels = [
    {
      title             = "CPU % (Avg)"
      type              = "timeseries"
      metric            = "CpuPercentage"
      metric_namespace  = "Microsoft.Web/serverFarms"
      panel_aggregation = "Average"    
      alerts = {
        Teams = {
          enabled              = true
          aggregation          = "Average"
          threshold            = 85
          reduction_expression = "last"
          eval_operator        = "gt"
          pending_period       = "10m"
          contact_point        = "default-not-in-use"
        }
      }
    },
    {
      title            = "HTTP Queue Length"
      type             = "timeseries"
      metric           = "HttpQueueLength"
      metric_namespace = "Microsoft.Web/serverFarms"
    },
    {
      title            = "Data In"
      type             = "timeseries"
      metric           = "BytesReceived"
      metric_namespace = "Microsoft.Web/serverFarms"
    }
  ]
}

definition of panels inside the grafana_dashboard module:

variable "app_service_plans_dashboard" {
  type = object({
    title         = string
    folder        = string
    template_json = string
    panels = list(object({
      title             = string
      type              = string
      metric            = string
      metric_namespace  = string
      alerts = optional(map(object({
        enabled              = optional(bool, false)
        panel_id             = optional(number, -1)
        pause_evaluation     = optional(bool, false)
        aggregation          = optional(string, "Average")
        threshold            = optional(number)
        interval_ms          = optional(number, 60000)
        reduction_expression = optional(string, "last")
        eval_operator        = optional(string)
        pending_period       = optional(string, "5m")
        contact_point        = optional(string)
        time_range           = optional(number, 21600)
      })), {})
    }))
  })
  default = null
}

The full error was:

The given value is not suitable for module.grafana_dashboards["app_service_plans"].var.dashboard_panels declared at ../../global_modules/grafana_dashboard/variables.tf:21,1-28: element types must all match for conversion to list

and the fix that I eventually came to was that the variable declared in variables.tf outside of the module was missing the panel_id attribute. I was under the impression that since that attribute existed in the module variables.tf as optional and with a default, that this should have worked anyway?

I’m sure there’s something I’m missing here, I was just curious as performing some testing with similar code, I was struggling to replicate it. The above are just excerpts from the code, so if it helps to include the whole configuration, I can provide that somewhere.

If anyone bothered to read all of that, thanks! :smiley: