Data, archive_file error or bug?

Hello, I’ve a problem with archive_file data source.
I’ve a condition which is creates a lambda layer:

resource "aws_lambda_layer_version" "layers" {
   for_each = { for layers, name in local.lambdas.options.layers : layers => name if local.lambdas.init.self && local.lambdas.extras.layers }
   filename = "not_working" #data.archive_file.layers[each.key].output_path
   source_code_hash = "not_working" #data.archive_file.layers[each.key].output_base64sha256
   ---
   Other code
   ---
}

resource "aws_lambda_layer_version" "layers" working as expected, and creates a lambda layer, if filename and source_code_hash are defined as shown above (Without using data source).

And I have a

data "archive_file"  "layers"  {
   for_each = { for layers, name in local.lambdas.options.layers : layers => name if local.lambdas.init.self && local.lambdas.extras.layers }
   type = lookup(each.value.archive, "type", null)
   ---
   Other code
   ---
}

As you can see, the for_each block are same with resource block, but I’v got an error:

each.value is object with 2 attributes

Finally here is my module block, where I call this resources


---
layers  = [
   {
      name        = "test-layer"
      runtimes    = [ "nodejs12.x" ]

      # * Archive Configuration(s)
      archive     = {
         type        = "zip"
         ---
         Other code
         ---
      }
   }
]
---

So my question is, why same for_each block working differently?

Hi @unity-unity,

What you’ve shared here is not the error message but rather a piece of extra context included to help you understand the error message. In order to help here, I’d need to see the full error message, which will start with the prefix Error:, followed by a configuration snippet including the “each.value is object” part you included, and then one or more paragraphs of text describing what the problem was.

1 Like

Hello, @apparentlymart I hope you’re doing well, thank you for helping me again, I owe you one.
So here is the actual error:

│ Error: Unsupported attribute
│
│   on ../../Resources/Serverless/Lambdas/main.tf line 36, in data "archive_file" "layers":
│   36:    type            = lookup(each.value.archive, "type",  null)
│     ├────────────────
│     │ each.value is object with 2 attributes
│
│ This object does not have an attribute named "archive".

This error seems to be saying that at least one of your objects in local.lambdas.options.layers doesn’t have an attribute named archive. I think in your question you’ve shared an expression that becomes var.layers in this module, but not the definition of local.lambdas which would include the local.lambdas.options.layers that this is referring to.

I think that you’re seeing the error for data.archive_file.layers and not for aws_lambda_layer_version.layers because the latter’s configuration doesn’t include a reference to each.value.archive, and thus it doesn’t matter that the attribute isn’t present in that case. Furthermore, Terraform can see that aws_lambda_layer_version.layers depends on data.archive_file.layers and so I expect it’s skipping the validation steps for aws_lambda_layer_version.layers once it’s concluded that data.archive_file.layers is not valid.

Can you verify that all of the elements of local.lambdas.options.layers have the attribute archive? If you’re not sure then please share the full definition of local.lambdas and I’ll try to see what might be going on with it.

1 Like

Hello, @apparentlymart again big thanks for your time.
Here is my local.lambdas.options.layers

locals{
  lambdas = {
    options = {
      layers  = flatten([ for lambdas in var.parameters.lambdas : [ for block in lambdas.layers : { name = lambdas["name"], layers = block } ] if lambdas.modules["layers"] ])
    }
  }
}

I’ve also made a debug output of: local.lambdas.options.layers of course with disabled archive_file

Changes to Outputs:
  + name = {
      + 0 = {
          + layers = {
              + archive     = {
                  + mode   = "0660"
                  + output = "handler.layer"
                  + source = "../Data/lambda"
                  + type   = "zip"
                }
              + description = "Handler initial layer"
              + license     = null
              + name        = "handler-init-layer"
              + runtimes    = [
                  + "nodejs12.x",
                ]
            }
          + name   = "handler"
        }
    }

Hi, @apparentlymart did you see any problems here?

Hi @unity-unity,

I reformatted your example a little just to make it a little easier for me to read. I’m including it here in case someone else reading this topic finds it useful:

locals {
  lambdas = {
    options = {
      layers = flatten([
        for lambdas in var.parameters.lambdas : [
          for block in lambdas.layers : {
            name = lambdas["name"]
            layers = block
          }
        ]
        if lambdas.modules["layers"]
      ])
    }
  }
}

If I’m folllowing correctly, this local value is then consumed by the for_each expression in the data block we were discussing earlier, which again I’m going to repeat here just to bring all of the relevant information closer together for easier reference:

data "archive_file"  "layers"  {
   for_each = {
     for layers, name in local.lambdas.options.layers : layers => name
     if local.lambdas.init.self && local.lambdas.extras.layers
   }

   type = lookup(each.value.archive, "type", null)
   # ...
}

I think one thing that seems confusing here is that you named the “value” symbol for the for expression name, but as far as I can tell that’s instead one of the objects from the local value definition above. That is, you’re setting name to be an object like we can see in your “Changes to Outputs”. I might suggest using a different symbol name than name for this, since name makes me think that the value will be a string. But that’s not the cause of the error, of course.

In the output value you shared, I see that each member of the collection is an object with attributes name and layers, and so the error message is correct to report that each.value.archive doesn’t exist and that each.value is an object with two attributes.

Instead, I guess you probably meant to refer to each.value.layers.archive, which I can see is a nested attribute of layers in your data structure. Again, I think the naming here is making things a little confusing, because it seems like this layers attribute refers only to a single “layer”, not to multiple layers, but accessing the attribute of the child object should avoid the error you saw before, even if you leave the intermediate attribute named layers for now.

Hi @apparentlymart


Yes I see the name value is confusing. So what I’m trying to do, is whenever the enduser opens dynamic block local.lambdas.options.layers enduser can add/adjust extra archive file on top of it. Goal is one Lambda function should have a multiple layers, inside of the layers must have archive file. Can you suggest how to fix this error, as I missing your point here