Terraform: Terraform 0.12.6: splat operator doesn't work when accessing attribute

Created on 22 Aug 2019  ·  6Comments  ·  Source: hashicorp/terraform

Terraform Version

Terraform v0.12.6
+ provider.aws v2.24.0

Terraform Configuration Files

variable "list" {
  type    = set(string)
  default = ["a", "b", "c", "1", "2", "3"]
}

provider "aws" {
  region = "eu-west-1"
}

locals {
  resources = concat(aws_s3_bucket.bucket.*.id)
}

resource "aws_s3_bucket" "bucket" {
  for_each = var.list
  bucket = "very-special-name-${each.key}"
}

output "resources" {
  value = local.resources
}

Debug Output

aws_s3_bucket.bucket["b"]: Refreshing state... [id=very-special-name-b]
aws_s3_bucket.bucket["c"]: Refreshing state... [id=very-special-name-c]
aws_s3_bucket.bucket["3"]: Refreshing state... [id=very-special-name-3]
aws_s3_bucket.bucket["1"]: Refreshing state... [id=very-special-name-1]
aws_s3_bucket.bucket["a"]: Refreshing state... [id=very-special-name-a]
aws_s3_bucket.bucket["2"]: Refreshing state... [id=very-special-name-2]

Error: Unsupported attribute

  on main.tf line 11, in locals:
  11:   resources = concat(aws_s3_bucket.bucket.*.id)

This object does not have an attribute named "id".

Expected Behavior

I was expecting that the output would return a list with the IDs of the buckets, but I get an error instead.

Actual Behavior

Error saying that the id doesn't exist.

Steps to Reproduce

  1. terraform init
  2. terraform apply -auto-approve

Additional Context

This is an example of the actual code I'm trying to run. The issue is that when using the splat operator, I cannot get any of the attributes.
I've tried:

aws_s3_bucket.bucket.*.id

```hcl
aws_s3_bucket.bucket.[*].id

```hcl
aws_s3_bucket.bucket[*].id

What's the problem? Am I doing something wrong?

Thanks.

config documentation enhancement

Most helpful comment

Hi @hmnp,

The resource "aws_s3_bucket" "bucket" block has for_each set, and so aws_s3_bucket.bucket in this case is a map of objects rather than a list of objects as it would be with count. The splat operator applies only to lists.

To get the id attributes from each of the objects in a map requires a for expression, like this:

[for b in aws_s3_bucket.bucket : b.id]

Or, alternatively (and possibly more usefully in some cases), you can produce a map from the key to the id so that other parts of the configuration can map from bucket key to id:

{ for k, b in aws_s3_bucket.bucket : k => b.id }

The splat syntax is essentially a shorthand for for expressions when the collection is a list or set and the operation to perform is accessing an attribute. The following two expressions are equivalent, but only if var.example is a list or set value:

var.example[*].id
[for v in var.example : v.id]

With that said, Terraform is working as designed here but we're going to label this issue to represent that we should check to make sure that this situation is covered adequately in the documentation for for_each. Thanks!

All 6 comments

Hi @hmnp,

The resource "aws_s3_bucket" "bucket" block has for_each set, and so aws_s3_bucket.bucket in this case is a map of objects rather than a list of objects as it would be with count. The splat operator applies only to lists.

To get the id attributes from each of the objects in a map requires a for expression, like this:

[for b in aws_s3_bucket.bucket : b.id]

Or, alternatively (and possibly more usefully in some cases), you can produce a map from the key to the id so that other parts of the configuration can map from bucket key to id:

{ for k, b in aws_s3_bucket.bucket : k => b.id }

The splat syntax is essentially a shorthand for for expressions when the collection is a list or set and the operation to perform is accessing an attribute. The following two expressions are equivalent, but only if var.example is a list or set value:

var.example[*].id
[for v in var.example : v.id]

With that said, Terraform is working as designed here but we're going to label this issue to represent that we should check to make sure that this situation is covered adequately in the documentation for for_each. Thanks!

Thanks for the reply.

Before I posted this question, I've read few threads on github regarding similar issues. For example, this answer kinda of describes the behaviour that I was expecting.
But, at same time, it looks like the behaviour is not very consistent.
For example:

When I read this, regardless of the resource type, it looks like what I was attempting should work.

In this case, for me to achieve what I want I've to follow the examples described above?

Thanks
Hugo

Hi @hmnp!

The examples you've referred to there are for situations when using count, not when using for_each. One documentation miss we noticed already is that References to Resource Attributes is still only covering the count situation, and not mentioning how to access for_each instances at all. So that'll be one of the places to update as part of closing this issue, but there may be others too.

This issue and the resolution helped me a lot too. I had read "References to Resource Attributes" from https://www.terraform.io/docs/configuration/expressions.html and only saw the splat example near the bottom which made me think doubly I was doing it correctly but wondering what was wrong. The part about the spat expression doesn't explicitly call out it is for resources that use the _count_ directive. Maybe if the section were split into two parts, one for _count_ examples and one for _for_each_ examples, a novice like myself would appreciate the distinction being made more quickly.

Very nice feature though!

You’re right @FrankReh, it’s a very helpful feature. I think the small issues that people have when using it, is that there are not many examples and the documentation could be more detailed.
I spent few hours trying to make it work, but now it works like a charm.

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