Terraform for_each with YAML queues: variable interpolation fails

Stuck on defining multiple Genesys Cloud queues from a YAML variable file using for_each in the Terraform CXone provider. I want to avoid hardcoding resources, so I’m loading a YAML map into Terraform via a custom data source and iterating over it. The plan crashes immediately with a type mismatch error.

  1. Load YAML config into local.queue_config using yamldecode(file("queues.yaml")).
  2. Define resource genesys_cloud_queue with for_each = local.queue_config.
  3. Set name = each.value.name and description = each.value.description.

Here is the snippet causing the issue:

resource "genesys_cloud_queue" "supervisor_queues" {
 for_each = local.queue_config
 name = each.value.name
 description = each.value.description
}

Error output:

Error: Invalid for_each argument

on main.tf line 12:
 12: for_each = local.queue_config

A "for_each" value is not supported on resources.

I’ve verified the YAML structure is a flat map of objects. Is the CXone provider blocking dynamic iteration for queue resources specifically, or is this a fundamental Terraform limitation I’m missing? I’m on TF 1.5.0 and provider v1.2.3.

I think the YAML decoder returns a generic map, which often breaks for_each type inference in Terraform when nested objects are present. The provider expects explicit attribute definitions, not raw maps.

Cause:
The genesys_cloud_queue resource requires specific types (string, bool) for attributes like name and description. Passing a raw map from yamldecode results in a type mismatch during the plan phase because Terraform cannot guarantee the schema matches the resource definition.

Solution:
Wrap the YAML data in a local map with explicit type casting. This ensures for_each receives a predictable structure.

locals {
 queues = { for k, v in yamldecode(file("queues.yaml")) : k => {
 name = tostring(v.name)
 description = tostring(v.description)
 enabled = tobool(v.enabled)
 } }
}

resource "genesys_cloud_queue" "dynamic_queues" {
 for_each = local.queues

 name = each.value.name
 description = each.value.description
 enabled = each.value.enabled
}

This pattern mirrors how we handle complex config objects in the Web Messaging SDK, ensuring type safety before initialization. Always validate the YAML keys against the provider schema to avoid silent failures.

3 Likes

This has the hallmarks of a standard type coercion issue where yamldecode returns a generic map that Terraform cannot statically analyze for for_each. You need to explicitly cast the decoded map to a specific structure using toset or a local variable with defined types before passing it to the resource block.

is spot on about the type inference breaking. yamldecode gives you a loose map, and Terraform’s static analysis chokes on that during the plan phase for for_each. you need to explicitly cast that map to a set of strings or objects before the resource block sees it.

here’s how i handle this in my serverless pipelines. don’t pass the whole decoded object directly. create a local variable that extracts just the keys or casts the structure. if your YAML is a simple map of queue configs, cast it to map(object({...})).

locals {
 # explicit casting forces terraform to validate the structure early
 queue_configs = {
 for key, value in yamldecode(file("${path.module}/queues.yaml")) :
 key => value if value.enabled == true
 }
 
 # ensure the keys are a set for for_each
 queue_keys = setkeys(local.queue_configs)
}

resource "genesyscloud_routing_queue" "dynamic_queues" {
 for_each = local.queue_keys
 
 name = local.queue_configs[each.key].name
 description = lookup(local.queue_configs[each.key], "description", null)
 
 # add your specific config here
 enable_workforce_management = true
}

the lookup with a default value helps if some queues don’t define a description. also, make sure your YAML keys are valid terraform identifiers (no spaces, start with letter/underscore). if they aren’t, use the key as a tag or description source instead of the resource name. i’ve seen this exact crash when the YAML had leading/trailing whitespace on keys. trim them if needed.

if you’re doing this at scale, consider adding a validation step in your CI pipeline to check the YAML structure before terraform runs. saves debugging time.

1 Like

the previous answers are spot on regarding the type inference issue, but they’re missing the practical side of managing these configs in a CI/CD pipeline. i don’t rely on terraform’s internal casting because it’s brittle when the yaml structure shifts. instead, i preprocess the yaml into a strict json map using python before it even hits the terraform state. this guarantees the types are exactly what the provider expects.

here’s the quick script i run in the pre-apply step:

import yaml
import json

with open('queues.yaml', 'r') as f:
 data = yaml.safe_load(f)

# enforce structure
cleaned = {k: v for k, v in data.items() if isinstance(v, dict)}
with open('queues.json', 'w') as f:
 json.dump(cleaned, f)

then just use jsondecode(file("queues.json")) in your locals. it removes the guesswork. also, watch out for special characters in queue names during the yaml parse; terraform will fail silently if the regex doesn’t match the gc api constraints.