Search code examples
terraform

Why does Terraform string interpolation syntax results in a list?


Consider the following example in terraform console:

> "${[1,2,3]}"
[
  1,
  2,
  3,
]

Why does Terraform evaluate this expression to be a list, and not a string representation of that list?

https://developer.hashicorp.com/terraform/language/expressions/strings#interpolation


Solution

  • What you've encountered here is a remnant of backward compatibility with Terraform v0.11 and earlier, which required using the interpolation syntax for all dynamic expressions, regardless of the result type.

    For example, if there was an argument called thingies that expected a list of strings and you wanted to assign it from a variable, you'd need to write it like this:

    # OBSOLETE EXAMPLE: This is for Terraform v0.11, which is
    # well past end of life and should not be used anymore.
    
    variable "thingies" {
      type = "list"
    }
    
    resource "example" "example" {
      thingies = "${var.thingies}"
    }
    

    Modern Terraform (v0.12 and later) allows arbitrary expressions without the need for interpolation syntax, but to stay compatible with some modules that were written for older versions, and to allow for a period where some modules were written for both v0.11 and v0.12 at once, Terraform continues to give this special treatment to any string template whose entire content is a single interpolation sequence.

    This special case is only for that specific situation. If your template gets even slightly more complicated then Terraform will reject this as an error:

    > "foo-${[1,2,3]}"
    ╷
    │ Error: Invalid template interpolation value
    │ 
    │   on <console-input> line 1:
    │   (source code not available)
    │ 
    │ Cannot include the given value in a string template: string required.
    ╵
    

    To use a list as part of a template, you must tell Terraform how to convert it to a string, since there are many different possible ways to do that:

    > "foo ${jsonencode([1,2,3])}"
    "foo [1,2,3]"
    > "foo ${yamlencode([1,2,3])}"
    <<EOT
    foo - 1
    - 2
    - 3
    
    EOT
    > "foo ${join(",", [1,2,3])}"
    "foo 1,2,3"
    > "foo ${join(", ", [1,2,3])}"
    "foo 1, 2, 3"
    

    The special case is no longer documented because Terraform v0.11 is now incredibly obsolete and so nobody should ever need to rely on this oddity. If you want a string representation of a collection or structural type, you should always use a function to describe to Terraform how to project the non-string value into a string.