Hint about failed conversion to list when returning error about mismatched tuple types in conditional
Terraform Version
Terraform v1.3.5
on darwin_amd64
Terraform Configuration Files
output "good_message" {
value = flatten([
for n in [{ o = [1] }, { o = [2] }] :
n.o[0] == 1
? [n]
: [merge({ a = 1 }, n)]
])
}
output "bad_message" {
value = flatten([
for n in [{ o = [1] }, { o = [2] }] :
n.o[0] == 1
? [n]
: [for k in [1, 3] : merge({ a = k }, n)]
])
}
Debug Output
not enabling TF_LOG because it's not necessary for this report.
$ tf validate
╷
│ Error: Inconsistent conditional result types
│
│ on main.tf line 26, in output "good_message":
│ 25: n.o[0] == 1
│ 26: ? [n]
│ 27: : [merge({ a = 1 }, n)]
│ ├────────────────
│ │ n.o[0] is 1
│
│ The true and false result expressions must have consistent types. Type mismatch for tuple element 0: The 'false' value includes object attribute "a", which is absent in the 'true' value.
╵
╷
│ Error: Inconsistent conditional result types
│
│ on main.tf line 26, in output "good_message":
│ 25: n.o[0] == 1
│ 26: ? [n]
│ 27: : [merge({ a = 1 }, n)]
│ ├────────────────
│ │ n.o[0] is 2
│
│ The true and false result expressions must have consistent types. Type mismatch for tuple element 0: The 'false' value includes object attribute "a", which is absent in the 'true' value.
╵
╷
│ Error: Inconsistent conditional result types
│
│ on main.tf line 35, in output "bad_message":
│ 34: n.o[0] == 1
│ 35: ? [n]
│ 36: : [for k in [1, 3] : merge({ a = k }, n)]
│ ├────────────────
│ │ n.o[0] is 1
│
│ The true and false result expressions must have consistent types. The 'true' tuple has length 1, but the 'false' tuple has length 2.
╵
╷
│ Error: Inconsistent conditional result types
│
│ on main.tf line 35, in output "bad_message":
│ 34: n.o[0] == 1
│ 35: ? [n]
│ 36: : [for k in [1, 3] : merge({ a = k }, n)]
│ ├────────────────
│ │ n.o[0] is 2
│
│ The true and false result expressions must have consistent types. The 'true' tuple has length 1, but the 'false' tuple has length 2.
╵
Expected Behavior
An error message for bad_message explaining that the problem was a missing field:
╷
│ Error: Inconsistent conditional result types
│
│ on main.tf line 35, in output "bad_message":
│ 34: n.o[0] == 1
│ 35: ? [n]
│ 36: : [for k in [1, 3] : merge({ a = k }, n)]
│ ├────────────────
│ │ n.o[0] is 1
│
│ The true and false result expressions must have consistent types. Type mismatch for tuple element 0: The 'false' value includes object attribute "a", which is absent in the 'true' value.
╵
Actual Behavior
The following error message, which, when embedded deep inside a for_each clause makes debugging pretty tricky.
╷
│ Error: Inconsistent conditional result types
│
│ on main.tf line 35, in output "bad_message":
│ 34: n.o[0] == 1
│ 35: ? [n]
│ 36: : [for k in [1, 3] : merge({ a = k }, n)]
│ ├────────────────
│ │ n.o[0] is 1
│
│ The true and false result expressions must have consistent types. The 'true' tuple has length 1, but the 'false' tuple has length 2.
╵
Steps to Reproduce
-
terraform init -
terraform validate(orterraform plan)
Additional Context
No response
References
No response
Thanks for this report!
Hi @skeggse!
Looking at the expression you wrote in bad_message, it seems like this error message is correct because:
- The two arms of the conditional have tuple types, but not the same tuple type.
- The tuple element types are not compatible with one another, so Terraform cannot automatically coerce this into a list of objects.
- Tuple types are not required to have homogeneous element types -- that's what differentiates tuple types from list types -- and so neither of the conditional arms are invalid when taken in isolation.
Because Terraform's attempts to guess what you might have meant and apply implicit type conversions failed, Terraform just fell back on returning the most direct description of the original problem: the conditional expression arms are of different tuple types.
While I can use my human intuition to infer from the context what you intended this expression to mean, I'm not sure how to express that as a rule we could write in code to produce the error message you proposed. It would require Terraform to guess that you intended these tuples to be converted to lists and that it's the failure to convert to list that was the problem, not the direct type inconsistency.
Being explicit that the conditional result arms are supposed to be lists gives Terraform the extra hint required to get the error message you wanted:
> flatten([
: for n in [{ o = [1] }, { o = [2] }] :
: n.o[0] == 1
: ? tolist([n])
: : tolist([for k in [1, 3] : merge({ a = k }, n)])
: ])
╷
│ Error: Inconsistent conditional result types
│
│ on <console-input> line 4:
│ (source code not available)
│
│ The true and false result expressions must have consistent types. Mismatched list element types: The 'false' value includes object attribute "a",
│ which is absent in the 'true' value.
╵
...but without that hint Terraform concludes that you must've intended the results to be tuples, because the automatic conversion to list failed.
I agree that what happened here isn't ideal, but I'm not really sure what to do about it. The best idea I have is to extend the error message to explicitly acknowledge the failed attempt at type conversion somehow. For example:
The true and false result expressions must have consistent types. The 'true' tuple has length 1, but the 'false' tuple has length 2. The tuples have mismatched element types, so automatic conversion to list is also impossible.
We've run into trouble in the past putting this sort of extra content in error messages because folks who only skim error messages tend to shut off and fail to process the message at all when there's more than one possibility to consider. But perhaps it would be okay in this case, since I'd imagine that intent to convert to a list is the more likely case than trying to select between two different tuple types.
(This error message actually belongs to HCL rather than to Terraform, so if we choose to make a change like I described above then we'll need to do it in the HCL repository rather than here.)