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

Panic when using for and for_each iterating through list(map(string)) #22347

Closed
jvelasquezjs opened this issue Aug 6, 2019 · 9 comments
Closed
Assignees

Comments

@jvelasquezjs
Copy link

Terraform Version

terraform -v
Terraform v0.12.6
+ provider.aws v2.22.0

Terraform Configuration Files

my module in `./module

variable "zone_id" {
  description = "The id of the zone to create records in."
}

variable "records_list" {
  description = "List records. Each record is a map formed by `name`, `record` and `ttl` optionally."
  type        = list(map(string))

  default = [
    {
      "name"   = "example"
      "record" = "1.2.3.4"
    },
  ]
}

variable "records_count" {
  description = "Number of records to create, has to be set to the number of records in the records_list."
  default     = 0
}

resource "aws_route53_record" "record" {
  # for_each = var.records_list

  for_each = [for r in var.records_list : {
    r_name   = lookup(r, "name", null)
    r_type   = lookup(r, "type", "CNAME")
    r_ttl    = lookup(r, "ttl", 60)
    r_record = lookup(r, "record", null)
  }]

  zone_id = var.zone_id
  name    = each.value.r_name
  type    = each.value.r_type
  ttl     = each.value.r_ttl
  records = each.value.r_record
}

using the module

resource "aws_route53_zone" "test" {
  name = "nowhere.example.co.uk"
}

module "test" {
  source        = "./module"
  zone_id       = aws_route53_zone.test.id
  records_count = 1

  records_list = [
    {
      "name"   = "aaa"
      "type"   = "CNAME"
      "record" = "bbb.nowhere.example.co.uk"
    },
  ]
}

Debug Output

Crash Output

https://gist.github.com/jvelasquezjs/262fdb16e7d18e1272c424e8d08fa18c

Expected Behavior

Not to panic...

Actual Behavior

Panic due to string not expected

Steps to Reproduce

terraform init
AWS_DEFAULT_REGION=eu-west-1 terraform plan

Additional Context

References

@wata727
Copy link
Contributor

wata727 commented Aug 9, 2019

This looks like the same issue as #22305.

@pselle pselle self-assigned this Aug 9, 2019
@pselle
Copy link
Contributor

pselle commented Aug 9, 2019

@wata727 is correct! This is fixed in master and will be released in 0.12.7 of Terraform (and I'll leave this open until that is out, and have self-assigned to do so).

To work around this, ensure that you are passing a set and not a list (which Terraform is interpreting as a tuple) to for_each using the toset() function.

Thank you for the report!

@pselle
Copy link
Contributor

pselle commented Aug 22, 2019

Terraform 0.12.7 (with this fix) is now released! https://github.com/hashicorp/terraform/blob/v0.12.7/CHANGELOG.md

@pselle pselle closed this as completed Aug 22, 2019
@sc250024
Copy link

sc250024 commented Aug 30, 2019

@pselle I have a very similar example to @jvelasquezjs (with the lookup function and everything) and I'm using Terraform v0.12.7, but for some reason, I'm getting this error:

The given "for_each" argument value is unsuitable: the "for_each" argument
must be a map, or set of strings, and you have provided a value of type tuple.

Can we not pass in a list(map(string)) type variable? How would you modify @jvelasquezjs 's example in the aws_route53_record to make it a set? I've tried the equivalent of:

  for_each = toset([for r in var.records_list : {
    r_name   = lookup(r, "name", null)
    r_type   = lookup(r, "type", "CNAME")
    r_ttl    = lookup(r, "ttl", 60)
    r_record = lookup(r, "record", null)
  }])

But I get the same error as above. And also this...

  for_each = toset(var.records_list)

But I get this...

The given "for_each" argument value is unsuitable: "for_each" supports maps
and sets of strings, but you have provided a set containing type map of
string.

@sc250024
Copy link

Actually I found a solution for my above comment here: #22610 (comment). However, I'm not sure why map(map(string)) is fine, but this example of list(map(string)) somehow breaks it.

@t5unamie
Copy link

t5unamie commented Sep 2, 2019

@sc250024 can you post the working example. Messing around with different options is not ver clear to me which code change worked for the original example.

@sc250024
Copy link

sc250024 commented Sep 2, 2019

@t5unamie Yep. I was using it to make a module for GitLab repositories.

vars.tf

variable "branch_protection_map" {
  default = {
    master = {
      merge_access_level = "developer"
      push_access_level  = "maintainer"
    }
  }
  description = "Map of branch / access-level mappings to protected branches."
  type        = map(map(string))
}

main.tf

resource "gitlab_branch_protection" "this" {
  for_each = var.branch_protection_map

  project            = gitlab_project.this.id
  branch             = each.key
  merge_access_level = lookup(each.value, "merge_access_level", "developer")
  push_access_level  = lookup(each.value, "push_access_level", "maintainer")
}

I guess Terraform needs a key as in the each.key part. Hopefully that works for you.

@t5unamie
Copy link

t5unamie commented Sep 3, 2019

@sc250024 thanks

@ghost
Copy link

ghost commented Sep 22, 2019

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 Sep 22, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants