Terraform: ternary type detection is broken, and when using ternary in output, errors are eaten

Created on 7 Apr 2017  ยท  7Comments  ยท  Source: hashicorp/terraform

Terraform Version

0.9.2

Affected Resource(s)

Please list the resources as a list, for example:

  • core

Terraform Configuration Files

variable "map" {
  type = "map"
  default = {
    map = { thing = "stuff" }
  }
}
data "null_data_source" "nds" {
  inputs = {
    d = "${1 > 0 ? var.map["map"] : map() }"
  }
}
output "map map" {
  value = "${var.map["map"]}"
}
output "map map ternary" {
  value = "${1 > 0 ? var.map["map"] : map() }"
}
output "map map ternary from nds" {
  value = "${data.null_data_source.nds.inputs.d}"
}

Debug Output

I'm not including debug output, it's easier to do on your own than download a gist

Panic Output

There's no panic

Expected Behavior

I should have gotten the map value for var.map["map"] in all cases

Actual Behavior

When the null_data_source is commented out, the "map map ternary" output simply fails to output anything. terraform exits normally, and only produces output for "map map"

When the NDS was added, here is the error:

1 error(s) occurred:

* data.null_data_source.nds: 1 error(s) occurred:

* data.null_data_source.nds: At column 3, line 1: true and false expression types must match; have type list and type map in:

${1 > 0 ? var.map["map"] : map() }

So the ternary type detection is broken, which is causing spurious errors. Furthermore, when you attempt a ternary in an output variable and the type detection brokenness is triggered, the error is simply swallowed, and the output never appears, as terraform claims a normal exit status.

Steps to Reproduce

Please list the steps required to reproduce the issue, for example:

  1. terraform apply

Important Factoids

Why do I keep finding these core bugs?

References

Couldn't find a thing

bug config

Most helpful comment

Issue is broader than nested maps. If it's not clear in the above discussion:

main.tf

terraform {
  required_version = ">= 0.10.7"
}

variable "config" {
  type = "map"
  default {
    Foo = "hello"
    Bar = "world"
  }
}

variable "config2" {
  type = "map"
  default {}
}

output "test_output" {
  value = "out"
}

output "test" {
  value = "${("true" ? var.config : var.config2 )}"
}

Terminal:

terraform apply

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

test_output = out

Semi-related note:
I was trying to get interpolation in default values by using a map in the locals feature and faced similar issues with the ternary operator... but this case may be more similar to the nesting of maps, I haven't looked at the internals.

All 7 comments

If someone would be kind enough to propose a workaround for this one, I'd be very glad.

Hi @in4mer! Sorry for all the confusing interactions here.

The fact that the error isn't returned when this expression appears in an output is the same root cause as #9080.

Unfortunately I think this other problem here, with your map being detected as a list, is a gross problem with the HCL parser. HCL has various "sloppy" interpretations of certain constructs to allow for different forms of configuration block, and in particular it often likes to turn single maps into slices of maps, as a side-effect of the fact that you can potentially repeat blocks:

foo {}
foo {}

I _think_ what's going on here is that HCL is interpreting what you intended to be a map of maps as a map of lists of maps, which the type checker in the interpolation language is then (correctly) rejecting.

In general deeply-nested structures like this don't work very well in Terraform right now. We have some plans to improve how types are represented internally, since today things are built on rather shaky foundations that date back to when Terraform only supported strings.

For now a workaround here is a bit tricky. Normally in this sort of situation we suggest using the map() interpolation function to bypass HCL's weird parsing rules, but interpolations are not allowed in variable defaults and so this solution won't work here.

So unfortunately I think for now my only suggestion is to avoid using multi-level nested data structures like this, and instead flatten the parameters to be lists of strings or maps of strings. I understand that this is an annoying restriction, and we are already discussing internally the solution to this class of problem to give Terraform a better handle on collection types.

errors are eaten

rage

Thank you very much for sending this bug report.

Issue is broader than nested maps. If it's not clear in the above discussion:

main.tf

terraform {
  required_version = ">= 0.10.7"
}

variable "config" {
  type = "map"
  default {
    Foo = "hello"
    Bar = "world"
  }
}

variable "config2" {
  type = "map"
  default {}
}

output "test_output" {
  value = "out"
}

output "test" {
  value = "${("true" ? var.config : var.config2 )}"
}

Terminal:

terraform apply

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

test_output = out

Semi-related note:
I was trying to get interpolation in default values by using a map in the locals feature and faced similar issues with the ternary operator... but this case may be more similar to the nesting of maps, I haven't looked at the internals.

Any update on this issue? We have the same issue on version 0.10.7

Hi all!

The core issue regarding conditional statements has been fixed.
The example in the original comment will not work, but now terraform gives a clear error message explaining that inputs must be strings:

Error: Incorrect attribute value type

  on main.tf line 9, in data "null_data_source" "nds":
   9:   inputs = {

Inappropriate value for attribute "inputs": element "d": string required.

The latter example works as expected:

variable "config" {
  type = "map"
  default = {
    Foo = "hello"
    Bar = "world"
  }
}

variable "config2" {
  type = "map"
  default =  {}
}

output "test_output" {
  value = "out"
}

output "test" {
  value = "${("true" ? var.config : var.config2 )}"
}
$ terraform output
test = {
  "Bar" = "world"
  "Foo" = "hello"
}
test_output = out

Based on that, I am going to close this issue. Please don't hesitate to open a new issue if you see any odd behaviors in terraform 0.12. Thanks!

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.

Was this page helpful?
0 / 5 - 0 ratings