Yamldecode - Cannot include the given value in a string template: string required

Hi, I have some very simple code to do some testing with and I am running into some issues.
My overall goal is to have config stored in a .yaml file which I then use templatefile to replace some variables and finally it will be jsonencoded.

main.tf

locals {
  test = yamldecode(templatefile("${path.module}/test.yaml",
    {
      admin_groups         = ["123456-7890"]
    }
  ))
}

output "test" {
  value = jsonencode(local.test)
}

test.yaml

GITLAB_OMNIBUS_CONFIG: |
  gitlab_rails['omniauth_providers'] = |
      admin_groups: ['${admin_groups}']

When terraform plan however I am getting the following error message:

│ Error: Error in function call
│ 
│   on main.tf line 2, in locals:
│    2:   test = yamldecode(templatefile("${path.module}/test.yaml",
│    3:     {
│    4:       admin_groups = ["123456-7890"]
│    5:     }
│    6:   ))
│     ├────────────────
│     │ path.module is "."
│ 
│ Call to function "templatefile" failed: ./test.yaml:3,25-37: Invalid template interpolation value; Cannot include the given value in a string template: string required..

Is there some way to interpolate this list of strings that I am not doing?
Cheers for any help.

Hi @fraserc182,

The template system is really just string concatenation, so it can only interpolate values that can be trivially converted to string.

There are many possible ways to serialize a list as a string, so if you want to use a list value in your template you will need to explain to Terraform what syntax you intend to use for it.

YAML is a superset of JSON so I think it would work to just JSON-encode the value at that position to produce valid YAML syntax:

GITLAB_OMNIBUS_CONFIG: |
  gitlab_rails['omniauth_providers'] = |
      admin_groups: ${jsonencode(admin_groups)}

With that said: constructing a YAML document using template interpolation and then immediately parsing it with yamldecode is a very unusual thing to do. I realize that you’re sharing a contrived test configuration and your real situation is probably more complicated, but a more typical and straightforward way to achieve this result would be to directly write an object constructor describing the data structure you’re intending to produce here.

If it being in a separate file is important then I would suggest considering the advice in Generating JSON or YAML from a template. The strategy described there – of making your entire template be a call to yamlencode – will avoid the need for you to carefully construct valid YAML syntax and allow you to instead just describe the data structure using a Terraform expression and let Terraform worry about generating valid YAML from it.

Hi @apparentlymart thanks very much for getting back to me, much appreciated. I’ll give what you suggest a try and see if that works. I agree this is absolutely not the best way to do things but I am struggling to find another solution.

For context, the reason I am doing this is to pass gitlab configuration variables into an ECS service definition template. However it expects it passed as yaml, but I cannot pass yaml to a service definition json file. Hence the decoding then encoding it back as json. It definitely isn’t the best way but I have been bashing against this for weeks now.

Thanks again.