Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Argument expansion error in output expression during validation walk #22404

Closed
apparentlymart opened this issue Aug 8, 2019 · 13 comments · Fixed by #25216
Closed

Argument expansion error in output expression during validation walk #22404

apparentlymart opened this issue Aug 8, 2019 · 13 comments · Fixed by #25216
Labels
bug config confirmed a Terraform Core team member has reproduced this issue v0.12 Issues (primarily bugs) reported against v0.12 releases

Comments

@apparentlymart
Copy link
Contributor

apparentlymart commented Aug 8, 2019

Terraform Version

$ terraform version
Terraform v0.12.7-dev

Terraform Configuration Files

variable "mapping" {
  default = {
    "a" = ["b", "c"]
  }
}

locals {
  mapping = [
    for x, y in var.mapping : [
      for z in y : {
        "${z}" = x
      }
    ]
  ]
}

output "x" {
  value = merge(flatten(local.mapping)...)
}

Debug Output

Crash Output

https://gist.github.com/apparentlymart/e1e86b3299c679df1b66d64e2ee86fb5

Expected Behavior

The value for output x after applying should be:

{
  "b" = "a"
  "c" = "a"
}

Actual Behavior

Terraform produces an error during the validation walk:

Error: Invalid expanding argument value

  on expand-arguments-error.tf line 18, in output "x":
  18:   value = merge(flatten(local.mapping)...)

The expanding argument (indicated by ...) must be of a tuple, list, or set
type.

Steps to Reproduce

Using the above configuration, run terraform apply

Additional Context

Interestingly, evaluating the same expression in terraform console works as expected:

$ terraform console
> merge(flatten(local.mapping)...)
{
  "b" = "a"
  "c" = "a"
}

The console is evaluating expressions in a different mode than in the validate walk, so perhaps there's something unusual about the validate walk that is making this fail.

This bug is likely to be upstream in the HCL repository, e.g. in the FunctionCallExpr evaluation logic. It looks like this isn't correctly handling the case where the expression to expand is cty.DynamicVal, so perhaps that's the root cause; if so, adding cty.DynamicPseudoType to the set of allowed types is probably enough to fix it, because there's already a test in there for if the value is unknown. If this theory does turn out to be true then this'll be a PR in the HCL repository first, and then a vendor update PR in here.

This value would be unknown here during the validation walk because it's derived from a variable, and variables don't get concrete values until the plan walk.

References

This was originally reported in a community forum topic.

@leoskyrocker
Copy link

Bumped into this. Currently I'm working around this by...

merge(flatten([local.mapping])...)

or in this case maybe a double flatten? but a single flatten is actually sufficient for me.

@hashibot hashibot added the v0.12 Issues (primarily bugs) reported against v0.12 releases label Aug 29, 2019
@rich-boyce
Copy link

rich-boyce commented Nov 25, 2019

Bug is still present in

$ terraform version
Terraform v0.12.16

@jbonilla03
Copy link

Error still present in v0.12.17, can anyone provide a solution or workaround ?

locals {
outputvnets = "${flatten(data.azurerm_virtual_network.testvnet[*].address_space)}"
}
variable "SUBNET_MASK" {
description = "address prefix for the vnet to be created. Examples: 17,18,19,20,21,22,23,24,25,26,27,28,29"
#type = number
default = 23
}
locals {
nexthop = "${var.SUBNET_MASK - 16}"
}
locals {
subnetlist = [for s in range(1,pow(2,local.nexthop)) : contains(local.outputvnets,cidrsubnet("10.1.0.0/16",local.nexthop,s)) ? "" : cidrsubnet("10.1.0.0/16",local.nexthop,s)]
}

Error: Invalid expanding argument value
on outputs.tf line 30, in output "myvnets":
30: value = coalesce("${local.subnetlist}"...)
The expanding argument (indicated by ...) must be of a tuple, list, or set
type.

PS C:\Users\vn50est\Source\Repos\terraform-azurerm-vnet> terraform version
Terraform v0.12.17

  • provider.azurerm v1.37.0

@ianwremmel
Copy link

Seeing something similar in 0.12.18. As far as I can tell, the only difference between the two examples is whether the follow data structure comes from a local or a variable

target_groups = {
  tg1 = ["api", "www"]
}

Working

locals {
  target_groups = {
    tg1 = ["api", "www"]
  }

  tuple_of_maps = [
    for target_group, domains in local.target_groups :
    { for domain in domains : domain => target_group }
  ]

  domains = merge(local.tuple_of_maps...)
}

resource "null_resource" "this" {
  for_each = local.domains
}

output "resources" {
  value = [for nr in null_resource.this : nr.id]
}

output:

null_resource.this["www"]: Creating...
null_resource.this["api"]: Creating...
null_resource.this["api"]: Creation complete after 0s [id=3280095703150378859]
null_resource.this["www"]: Creation complete after 0s [id=6840764206472798878]

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

Outputs:

resources = [
  "3280095703150378859",
  "6840764206472798878",
]

Not Working

variable "target_groups" {
  default = {
    tg1 = ["api", "www"]
  }
  type = map(list(string))
}

locals {
  tuple_of_maps = [
    for target_group, domains in var.target_groups :
    { for domain in domains : domain => target_group }
  ]

  domains = merge(local.tuple_of_maps...)
}

resource "null_resource" "this" {
  for_each = local.domains
}

output "resources" {
  value = [for nr in null_resource.this : nr.id]
}

output:

Error: Invalid expanding argument value

  on test.tf line 20, in locals:
  20:   domains = merge(local.tuple_of_maps...)

The expanding argument (indicated by ...) must be of a tuple, list, or set
type.

@leoskyrocker's workaround appears to fix my contrived example.

@ianwremmel
Copy link

Huh, looks like I was really tired yesterday when I effectively reposted the original example without recognizing I'd done so 🤦‍♂ .

Could this bug be related to #22576?

@a-abella
Copy link

a-abella commented Jan 28, 2020

Bumped into this. Currently I'm working around this by...

merge(flatten([local.mapping])...)

or in this case maybe a double flatten? but a single flatten is actually sufficient for me.

@leoskyrocker You are a savior. I just spent hours trying to figure out was wrong with my expressions. Can confirm this workaround works and saved my sanity.

@zelig81
Copy link

zelig81 commented Jan 28, 2020

terraform 0.12.20 - still not works. The workaround still works (the formula above)

@apparentlymart
Copy link
Contributor Author

I believe this should be fixed by hashicorp/hcl#386 once Terraform's HCL dependency is upgraded to a version including that change.

@iridian-ks
Copy link

I'm on version v0.12.26.

I don't think the workaround is working for me :'(

  splunk_vault_secrets_in = flatten(flatten(flatten(flatten([
    for i, splunk in local.splunk :
    {
      "splunk_${i}_token" = splunk.token
    }
  ]))))
  splunk_vault_secrets = merge(flatten(flatten(local.splunk_vault_secrets_in))...)
Error: Invalid expanding argument value

  on ../../modules/role-kube/main.tf line 212, in locals:
 212:   splunk_vault_secrets = merge(flatten(flatten(local.splunk_vault_secrets_in))...)

The expanding argument (indicated by ...) must be of a tuple, list, or set
type.

@web-sst
Copy link

web-sst commented Jun 7, 2020

Passing the list through flatten() does not resolve the issue for me, but passing it through a utility module that calls merge does. I called it merge_list.

 variable data {
    type = list(any)
  }

 locals {
   result = merge(var.data...)
 }
 
 output result {
   value = local.result
 }

module merge_list {
  source = ".../merge_list"

  data = local.my_list_to_merge
}

locals {
  my_merged_list = module.merge_list.result
}

@mltsy
Copy link

mltsy commented Jun 11, 2020

@web-vertalo @iridian-ks I think, because this is a weird syntax-parsing error, part of the key to the workaround is wrapping your value in a list literal before flattening and merging: flatten([this]), not flatten(this). Maybe you've tried that, or maybe I'm wrong. But I noticed at leasts @iridian-ks's example was missing that.

@oofnikj
Copy link

oofnikj commented Jul 9, 2020

Ran in to this with Terraform 0.12.28 on Linux x86_64 with the following snippet:

locals {
  azs           = length(data.aws_availability_zones.azs.names)
  total_subnets = (var.private_subnets + var.public_subnets)
  newbits       = [for i in range(local.total_subnets) : ceil(log(local.total_subnets, 2))]
  subnet_cidrs = cidrsubnets(var.cidr_block, local.newbits...)
}

Changing the last line to

  subnet_cidrs = cidrsubnets(var.cidr_block, flatten([local.newbits])...)

fixes the issue.

Also the original code (without flatten([])) works in v0.13.0-beta2.
Thanks to @leoskyrocker for the workaround, and to all Terraform devs for continued awesome work!

@ghost
Copy link

ghost commented Jul 12, 2020

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.

@ghost ghost locked and limited conversation to collaborators Jul 12, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug config confirmed a Terraform Core team member has reproduced this issue v0.12 Issues (primarily bugs) reported against v0.12 releases
Projects
None yet
Development

Successfully merging a pull request may close this issue.