Last week, on my job, I encountered this error and couldn’t find a solution available online, so I decided to write the solution I came up with.
Problem
When we have a ternary, both results must have the same structure.
locals {
ingress_config = var.is_open ? {
enabled: true
config: {
path: "/dashboard"
}
} : {
enabled: false
}
}
That leads to:
This only happens when there is an inner map in the map, which makes sense because if we instead had:
locals {
ingress_config = var.is_open ? {
enabled: true
path: "/dashboard" # Specified directly
} : {
enabled: false
}
}
Terraform could infer that path
is optional and in the “else” block is null.
Context
This arose in my job, with that exact example, we were creating a module for provisioning a Helm release (for releasing our Chart), which had the ingress as optional, since the Chart had a structure similar to the example above, it led to that error.
After a thorough search, I couldn’t find any fix that didn’t involve changing the structure. (which isn’t really a fix)
Thus, I thought of a creative solution.
Solution
The idea for this solution came to mind while dealing with encodings – the Helm provider deals with YAML directly, so I always have to encode this map to YAML.
The fix for this is using yamlencode
in those objects and then yamldecode
the ternary result. This way, both ternary results are strings.
locals {
ingress_config = yamldecode(var.is_open ? yamlencode({
enabled: true
config: {
path: "/dashboard"
}
}) : yamlencode({
enabled: false
}))
}
Now the plan
passes and we can see the result is exactly what we want.
True case
False case
Conclusion
We’ve just seen how to get around this Terraform error by leveraging the YAML encoding.
While Terraform is great for provisioning Infrastructure as code, when it comes to dealing with types, it lacks some flexibility. Fortunately, there is always a way around it!
Side note: If you’re wondering why I needed to decode the YAML again, despite mentioning that the Helm provider handles YAML directly, it’s because we had numerous maps that needed to be merged into a single map.