Terraform apply => module.format_data is a list of object, known only after apply

Hi everyone,

I have issues with data output when these data come from modules. For some, it works well, for other, I get the strange error message in the title. Of course I use “terraform apply” : )

value = module.fw_mgmt.net_info_full_list
│     ├────────────────
│     │ module.format_data is a list of object, known only after apply

The module’s code, without variables declaration, is:

locals {
  net_info_full_list = flatten([
    for available_net in var.available_net_list : [
      for vsphere_network in var.networks_list : {
        name          = available_net.name,
        cidr          = available_net.cidr,
        obj_prefix    = available_net.obj_prefix,
        platform_id   = available_net.platform_id,
        vSwitch       = available_net.vSwitch,
        vlan_id       = available_net.vlan_id,
        id            = vsphere_network.id,
        datacenter_id = vsphere_network.datacenter_id
      } if available_net.name == vsphere_network.name
    ]
  ])
}

output "net_info_full_list" {
  value = [ local.net_info_full_list ]
}

Parent’s code for output is:

output "net_info_full_list" {
  value = module.format_data.net_info_full_list
}

In short, “var.networks_list” is a list of vsphere_network objects created inside some module which outputs a list of vsphere_network objects and then the root module writes it on standard output (“for some, it works” ; )

But for this module (and a lot of others during these last weeks), I can’t get rid of this error.

Any idea of what I’m doing wrong?

Cheers

Hi @mathias213,

What you’ve included in your message here is only the informational portion of the error message which tries to explain which part of your configuration raised the error. You haven’t included the actual error message.

A Terraform error message starts with the prefix "Error: " followed by a summary, and then the context information you included here, often followed by some paragraphs of detailed information. The full error is delimited by the symbols at the left margin.

If you can post an update including the full error message then hopefully I can explain the meaning of that error.

Hi @apparentlymart,

Here is the full error message:


│ Error: Unsupported attribute

│ on main.tf line 358, in output “net_info_full_list”:
│ 358: value = module.format_data.net_info_full_list
│ ├────────────────
│ │ module.format_data is a list of object, known only after apply

│ This value does not have any attributes.

Maybe the “if” in my definition of local list of variables is responsible of this. It refers to vsphere_network objects which aren’t existing yet.

Thank you for your attention, cheers,

mathias

Hi @mathias213,

This error message says that module.format_data doesn’t have any attributes and so it isn’t valid to write module.format_data.net_info_full_list. It then gives us the additional context that module.format_data is a list of objects, which explains the immediate error because you have a list of module.format_data objects and so you need to specify which one you intend to take the net_info_full_list value from.

What makes sense here will depend on some other context that’s not shown in your message here, so I can’t make a strong recommendation but I’ll describe a few common options:

  • If you can have multiple instances of this module and you need to see the results from all of them in this output value then you can use the splat operator [*] to concisely transform the list of modules into a list of net_info_full_list output values alone:

    output "net_info_full_lists" {
      value = module.format_data[*].net_info_full_list
    }
    
  • Alternatively, if this is a list because you’ve used count to choose between zero or one items (which often involves a conditional expression like count = var.condition ? 1 : 0 and thus you only want to return the single net_info_full_list if it’s enabled then you can combine the splat operator from the previous example with the one function to tell Terraform that you expect only zero or one items and to use the one item alone if present:

    output "net_info_full_lists" {
      value = one(module.format_data[*].net_info_full_list)
    }
    

    The one function here means that in cases where count is zero the output value will take the value null, which represents that the output value isn’t set at all in that situation.

Hi @apparentlymart,

Thank you so much! Indeed it was the fact this module was launched several times through a count and using module.module_name[*].output_name was the solution : )

And also thank you for the one() function, I’ll experiment it soon. It sounds like it may help with null value in structured data (I’m still struggling with that too, but that’s another topic ^^)

Cheers,

mathias