Closed mkielar closed 1 year ago
I find at least few things problematic with the above:
map
type, it converts the values into that map. In that case, it converts them all to string
which allows converting bool
s and number
s. So in that case, terraform makes a decision to fall-back to a less restrictive datatype. However, when faced with <expr> ? <object> : {}
it somehow identifies the {}
as map, and decides to fall-back to map
type. But out of the two (map
, object
) the less restrictive one would be the object
, not the map. So why does terraform sometimes fall-back to _less restrictive` datatype, and sometimes to more restrictive one? That's inconsistent and error prone.{}
is a map, and not an empty object. Especially, when there is a tomap()
function - which convers object
s to map
s - but there's no toobject()
function that would do otherwise. Lack of toobject()
and existence of tomap()
suggests that anything I define using curly braces should initially be of object
type, and only explicit conversion using tomap()
or implicit conversion when using in contexts like merge()
should trigger conversion. Instead, { x: 1, y: "foo"}
is an object, and { x: 1 }
is an object, and any other combination of attributes is always an object, even type({})
returns object({})
. But when {}
is used in a inline "if" expression, it is somehow a map, and forces conversion of the other value in the expression? It should not be like that...Hi @mkielar,
I think the misunderstanding here is that {}
is an empty object, not a map, and that is the cause of your problem. The expression must always result in a single type, and because the value { x: 1234, y: true, z: "haha" }
is not the same type as {}
, terraform must try convert them to the same type, and the only possible type for unification here is a map(string)
. If no unification is possible, then you get the Inconsistent conditional result types
error.
We have an open enhancement request here to work on clarifying the type unification process in #28337, and #29622 to try and make the errors easier to understand in more complex situations.
Thanks!
@jbardin can you please elaborate a bit more on how the value { x: 1234, y: true, z: "haha" }
is not the same type as {}
?
When I run type()
function on both of them, it returns object
in both cases...
When you use the console type()
function the output for these is different:
> type({ x: 1234, y: true, z: "haha" })
object({
x: number,
y: bool,
z: string,
})
> type({})
object({})
object
is a kind of type, but object({})
is a different structural type from object({x: number})
and from object({x: number, y: bool})
and so on.
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
N/A, just open
terraform console
Debug Output
In
terraforfm console
run:Observe that the returned object has all the attributes correctly typed.
In
terraform console
run:It seems terraform is trying to do something weird... Like it would try to cast the first value into a map, with all values having the same type? Or same keys? The error message in this case is completely confusing.
In
terraform console
, run:Observe, that the value returned is in fact a
map
, not anobject
. But why? Also, all the values in the map have been casted tostring
!In
terraform console
run:Observe that this time, terraform returned an object. The
toobject({})
would cause error if executed (because there's no such function), but in this case, terraform somehow managed to figure out the first value is an object?Expected Behavior
In each case, terraform should return an object, and never should cast the values to string.
Actual Behavior
Actual behaviour is weird and confusing.
toobject()
not being defined, but no such thing happens.Steps to Reproduce
See "Debug output".
Additional Context
I spotted that when building payloads for
input
argument ofaws_cloudwatch_event_target
. I have a bunch of EventRule Schedules, and I noticed the JSON documents I pass as Lambda Events in these Rules have all values casted tostring
, regardless of what I set in terraform. I even tried explicit casts usingtonumber
andtobool
, only to see them all converted intostrings
.This was my setup:
After I changed the
} : {}
lines to} : null
it all magically started to work as expected. But the fact that it didn't in the first place is terribly confusing. Also, I'm now reviewing, fixing and adding code comments in places like this across my entire codebase, so that noone would accidentally "fix" the? { ... } : null
expressions back into? { ... } : {}
, and break stuff.References
No response