Terraform: Module output variables cannot be used to create a list input

Created on 14 Dec 2017  ·  11Comments  ·  Source: hashicorp/terraform

Hi all,

I cannot seem to pass through a list of strings when the strings are outputs of another module.

Terraform Version

Terraform v0.11.1

Terraform Configuration Files


Module Firewalls vars.tf:

variable "tags" {
  description = "List of tags to apply to the firewall"
  type        = "list"
}

Module Firewalls main.tf:

resource "digitalocean_firewall" "wall1" {
  name = "FIRE1"

  tags = "${var.tags}"

  ...
 }

root.tf

module "tags" {
  source = "./tags"
}

module "firewalls" {
  source = "./firewalls"
  tags     = ["${module.tags.firewall_tags}"]
}
  • Module tags has the output variable of firewall_tags which is type string
  • Module firewalls has the input variable tags which is of type List

Expected Behavior

Expected the ["${module.tags.firewall_tags}"] to be resolved as a string list

Actual Behavior

Error: module.firewalls.digitalocean_firewall.wall1: tags: should be a list

Steps to Reproduce

terraform plan

Important Factoids

I have found two instances where this behaviour does not appear and all is fine:

Hard-Coded List:root.tf

module "tags" {
  source = "./tags"
}

module "firewalls" {
  source = "./firewalls"
  tags     = ["HARDCODED"]
}

Using locals:root.tf

module "tags" {
  source = "./tags"
}
locals {
   temp = "LOCAL"
}
module "firewalls" {
  source = "./firewalls"
  tags     = ["${local.temp}"]
}
bug config

Most helpful comment

Hi, same problem here. Any ETA on this? It's really a tough issue to identify, specially for newcomers like me 😅

All 11 comments

Hi @TheYorkshireDev,

Can you show the configuration that's generating the module.tags.firewall_tags list? A simple hard-coded output works as expected, but there are still some edge cases where type information is list between modules.

I'm not sure if it effects the results you see, but you don't want the square brackets around "${module.tags.firewall_tags}" if that is already a list.

@jbardin I checked the state file and it was just as string, but here is the config.

Module.Tags main.tf

resource "digitalocean_tag" "firewall" {
  name = "FIREWALL"
}

Module.Tags output.tf

output "firewall_tags" {
  value = "${digitalocean_tag.firewall.name}"
}

Ah, got it. Yes, it looks like when the value is computed, the fact the square brackets turned it into a list was lost.

Hi, same problem here. Any ETA on this? It's really a tough issue to identify, specially for newcomers like me 😅

Is there a workaround for this?

@jspenc72 csv: join and split everywhere.

@soulrebel can you post an example?

I have same issue with list of maps (@soulrebel and join won't work in my case)...
I try to pass to module something like that:
``` [

{

name = "store.host"

value = "${google_redis_instance.search.host}"

},

                           {
                             name = "store.port"
                             value = "${var.store_port}"
                           },
                           {
                             name = "HOST2"
                             value = "http://${var.host2}/de"
                           },
                           {
                             name = "HOST1"
                             value = "http://${var.host1_name}:8983/"
                           }
                         ]

In module I have:

env = "${var.env_var}"


Basically when I hashout (as it is hashed out on example above) the map which contains output from another module and pass data containing only strings or variables then it works, other wise I get:

spec.0.template.0.spec.0.container.0.env: should be a list
```

This issue really makes the value of modules very limited. For example, if I create an AWS VPC with subnets in one module and then need to pass the subnet IDs into the module to create my EKS cluster, you can only do it if you hardcode the number of subnets and pass each in a separate output variable.

It seems that passing an output as a list that is used as input to another module works fine if the list is all hard-coded strings. As soon as you try to use interpolation syntax--even for the individual list items--it no longer works. For example, assume you have some code that looks similar to this:

In module A:
output "foo" {
...
}

In module B:
variable "bar" {
type = "list"
}

resource "aws_eks_cluster" "mycluster" {
....
vpc_config {
subnet_ids = "${var.bar}"
}
}

In main code:

module "A" {
...
}

module "B" {
...
bar = "${module.A.foo}"
}

If the output foo is defined like this (which clearly doesn't help), the code above works as expected:

output "foo" {
value = [ "subnet-12345678", "subnet-23456789", "subnet-34567890" ]
}

If if the output foo is defined using interpolation syntax like either of the two examples below, you get the "should be a list" error.

output "foo" {
value = [ "${aws_subnet.subnet-1.id}", "${aws_subnet.subnet-2.id}", "${aws_subnet.subnet-3.id}" ]
}

or:

output "foo" {
value = "${list("${aws_subnet.subnet-1.id}", "${aws_subnet.subnet-2.id}", "${aws_subnet.subnet-3.id}")}"
}

I ended up having to abandon the use of well-defined modules for any situation where I need to pass lists of things as outputs that need to be used as inputs to other modules.

I tried the join/split workaround but was unable to get that to work properly either.

Hi all! Sorry for the long silence here.

This issue has the same root cause as #12263, which has now been fixed in master ready for inclusion in the forthcoming v0.12.0 release. Thanks for reporting it, and thanks for your patience while we figured out what was going 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.

Was this page helpful?
0 / 5 - 0 ratings