-
Notifications
You must be signed in to change notification settings - Fork 9.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inconsistent conditional result types fails for complex types #22405
Comments
maybe stop checking for deeper level type consistency ? |
This issue is still happening in v 0.12.9 Error: Inconsistent conditional result types
on ../../ec2/aws_autoscaling_group/main.tf line 35, in locals:
35: for template in lookup(policy, "launch_template", null) != null ? [policy.launch_template] : [{}]: {
|----------------
| policy.launch_template is object with 2 attributes
The true and false result expressions must have consistent types. The given
expressions are tuple and tuple, respectively. |
The only way around this that I can see is to convert it to a map, list, or use the same number of values in the tuple in the default. But if you don't know what that will be, then using either object, or map might be the only possible workarounds. 😒 |
You can't use map.. you'll eventually hit the same silly wall. |
I just ran across this same problem in TF 0.12.9 but with objects instead of tuples. What I'd like to do is build a large arbitrary object structure in Terraform, and then json_encode it. The catch is that some parts of my object structure might be omitted entirely depending on variables. variable "tags" { default = { Name = "joe" } }
variable "LAN1_ip" { default = "192.168.1.1" }
variable "syslog_server" { default = "192.168.2.2" }
locals {
member_json = merge({
host_name = var.tags["Name"]
platform = "VNIOS"
config_addr_type = "IPV4"
vip_setting = {
address = var.LAN1_ip
}
use_dns_resolver_setting = true
},
var.syslog_server == "" ? {} : {
use_syslog_proxy_setting = true
external_syslog_server_enable = true
syslog_servers = [{
address = var.syslog_server
connection_type = "TCP"
port = 11006
severity = "INFO"
message_node_id = "HOSTNAME"
message_source = "ANY"
}]
},)
member_json_encoded = jsonencode(local.member_json)
}
output "json" { value = local.member_json_encoded } I hoped the above would just work in TF 0.12, but it doesn't:
It's possible to kludge around this by doing the string encoding before the conditional
but that doesn't scale past one or two conditionals. With regard to the new type system in general: I definitely see the value of being able to declare e.g. list(string) or map(string) in situations where that is desirable and appropriate, but forcing my ad-hoc objects and tuples to adhere to a consistent schema doesn't help me get work done efficiently. |
still nothing? :( |
This issue also affects Fixed the title (had a typo) |
This issue affects also Error: Inconsistent conditional result types
on outputs.tf line 9, in output "default":
9: value = length(google_project.default) > 0 ? google_project.default[0] : {}
|----------------
| google_project.default is tuple with 1 element
| google_project.default[0] is object with 11 attributes
The true and false result expressions must have consistent types. The given
expressions are object and object, respectively. |
@here A quick dirty fix for these kind of things is to replace this output "default" {
value = length(google_project.default) > 0 ? google_project.default[0] : {}
} with this output "default" {
value = jsondecode(length(google_project.default) > 0 ? jsonencode(google_project.default[0]) : jsonencode({}))
} |
I have workaround for this. output "default" {
value = try(length(google_project.default) > 0 ? google_project.default[0] : tomap(false), {})
} When condition = true, ?: evaluates normally. When condition = false, ?: goes to false condition, fails on tomap(false), then try() handles this and finally returns fallback which is empty object {} |
Love the workaround, but would this ever break in upcoming changes? |
Just a FYI, this is how iterate over maps with if conditions.
|
I ran into this issue today
|
@ibacalu thank you for reporting this. I apologize for how long the response has taken. I've reproduced this on 0.12.25 using the original reproduction case. I appreciate how clear of a case you put together. I'm putting this on our backlog. |
@danieldreier do you think that this fix would probably be available in 0.13 only? |
Can someone explain to me why the objects themselves have to exactly match instead of just the object type? Why does it matter if the different maps have 2 and 15 keys for a conditional to be evaluated? |
I stumbled upon this too ... trying to conditionally merge complex structures in 0.13-beta3: If i'm getting this right, most of these cases could be covered and solved by the DeepMerge PR #25032 ? addresses = merge(
local.workspace.enable_bastion_host == "true" ? {
"bastion1-internal-ip" = {
project_id = module.projects["service1"].project_id
address_type = "INTERNAL"
subnetwork = module.vpc_net1.subnetworks["vpc-subnet1"].self_link
labels = local.workspace_maps.global_labels
},
"bastion1-external-ip" = {
project_id = module.projects["service1"].project_id
address_type = "EXTERNAL"
labels = local.workspace_maps.global_labels
}
} : {},
local.workspace.enable_classic_vpn == "true" ? {
"classic-vpn-ip" = {
project_id = module.projects["host1"].shared_vpc_host_project_id
address_type = "EXTERNAL"
labels = local.workspace_maps.global_labels
}
} : {}
) Error: Inconsistent conditional result types
on main.tf line 240, in module "compute_addresses":
240: local.workspace.enable_bastion_host == "true" ? {
241: "bastion1-internal-ip" = {
242: project_id = module.projects["service1"].project_id
243: address_type = "INTERNAL"
244: subnetwork = module.vpc_net1.subnetworks["vpc-subnet1"].self_link
245: labels = local.workspace_maps.global_labels
246: },
247: "bastion1-external-ip" = {
248: project_id = module.projects["service1"].project_id
249: address_type = "EXTERNAL"
250: labels = local.workspace_maps.global_labels
251: }
252: } : {},
|----------------
| local.workspace.enable_bastion_host is true
| local.workspace_maps.global_labels is object with 1 attribute "managed-by"
| module.vpc_net1.subnetworks is object with 2 attributes
The true and false result expressions must have consistent types. The given
expressions are object and object, respectively. |
Happened to me too, while concatenating
Gives: Temporary workaround: remove the conditional... Complete example
Works:
|
Happening in |
Still happening in version 0.13.1
and I have:
|
I faced a similar issue using maps, i just fixed using variable deploy_charts {
type = bool
default = false
}
variable "charts" {
description = "A list of helm chart"
type = any
}
resource "helm_release" "chart" {
for_each = var.deploy_charts ? var.charts : tomap()
} Hope it helps! EDIT: This is not a fully working solution. It breaks when changing the boolean :( |
Hi all! I'm sorry for this confusing behavior, but terraform is behaving correctly in this case. The problem is not the conditional, but the incomplete variable definition. Terraform cannot convert the rules in your conditional statement to a list (which is what you are telling terraform with This example gets the result you are looking for. Note that we're now using variable "default_rules" {
default = null // instead of []
type = tuple([object({
a = string,
b = bool,
c = map(string),
}),
object({
d = string,
e = bool,
f = list(string),
}),
])
}
// Note that while this variable doesn't have "type" set, the default is the exact same type as
// default_rules above
variable "other_rules" {
default = [
{
a = "some string"
b = true
c = {t = "using map makes it fail"}
},
{
d = "some other string"
e = false
f = ["using list also makes it fail"] // I've modified your example because [t = "something] is not a valid list
}
]
}
output "rules" {
value = var.default_rules == null ? var.other_rules : var.default_rules
} Which you can see on terraform apply:
Since terraform is behaving as expected, I am going to close this issue. If you have further questions about this, I recommend that you ask in the community forum where there are far more people ready to help, whereas the GitHub issues here are generally monitored only by our few core maintainers. |
@mildwonkey Please explain why How specific does the variable definition need to be? Could I not also have:
The only thing that makes sense here is if terraform is converting lists into tuples when comparing the values of a conditional. The docs say If this is the case, why are lists converted to tuples? What if I want to have the values of a conditional to be lists with a different number of elements? |
I'm sorry that I did not explain things properly, @rabidscorpio , I made a faulty statement. I said "list", but the variable in your example is a tuple, not a list. The empty tuple, and the 2 tuple, have different types and cannot be converted to match. You are correct about the below example, which you supplied, working: variable "default_rules" {
default = null // instead of []
type = tuple([map(any),map(any)])
} I'm sorry for the confusion, and I also want to acknowledge that there are improvement we can (and should) make in the UX around the type system. I understand that terraform's error messages are frequently unclear, and it's something we are continually working on improving. |
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further. |
Terraform Version
Terraform Configuration Files
Debug Output
Crash Output
Expected Behavior
Actual Behavior
Steps to Reproduce
Additional Context
This issue is giving me an impossible headache. I am trying to set a default value for a variable(which can't be defined using variable block), and allow the user to override it.
References
#19180
The text was updated successfully, but these errors were encountered: