Referencing outputs from a for_each module

I have a module which has a variable defined using for_each , and its output is as below:

output "nic_ids" {
    value = [for x in azurerm_network_interface.nic :]
nic_ids = [

My aim is to pass above NIC ids to the VM module and have 1:1 mapping between NIC id and VM ( test-nic-1 should only be attached to vm-1 , test-nic-2 to vm-2 etc.)

module "vm" {
  source  = "*****/vm/azurerm"
  version = "0.1.0"
   vms = var.vms
   nic_ids = module.nic[].nic_ids 

I am getting below error:

Error: each.value cannot be used in this context

  on line 58, in module "vm":
  58:    nic_ids = module.nic[].nic_ids 

A reference to "each.value" has been used in a context in which it
unavailable, such as when the configuration no longer contains the value in
its "for_each" expression. Remove this reference to each.value in your
configuration to work around this error.

Can you please suggest?

Hi @JiJo333

does your module "vm" create multiple VMs on it’s own or should that module actually get instantiated multiple times? It sounds like multiple NICs are created within the NIC module. You’d also have the option to create multiple instances of the module, though.

Your code doesn’t include any for/for_each of the module, hence is invalid.

Based on that, wouldn’t you just pass the output of module.nics to vm?

module "vm" {
  source  = "*****/vm/azurerm"
  version = "0.1.0"
   vms = var.vms
   nic_ids = module.nic.nic_ids 

Thanks @tbugfinder for looking into this.
Yes, my VM module also has a similar structure allowing me to create multiple VMs.
Here is my file from the VM module:

variable "vms" {
  type = map(object(
      vm_name        = string
      location       = string
      rg_name        = string
      admin_username = string
      os_disk_name   = string
variable "admin_password" {
  type = string
variable "nic_ids" {
  type = list(string)

I am defining var.vms as

vms = {
    vm1 = {
        vm_name = "test-vm-1"
        location = "eastus2"
        rg_name = "test-rg"
        admin_username = "*******"
        os_disk_name = "test-vm-1-osdisk"
    vm2 = {
        vm_name = "test-vm-2"
        location = "eastus2"
        rg_name = "test-rg"
        admin_username = "*****"
        os_disk_name = "test-vm-2-osdisk"

What you mentioned below works, but that’s not exactly what I want

nic_ids = module.nic.nic_ids

It associates both the nic_ids to the same VM . . . I want first nic_id with VM-1 and second nic_id with VM-2.
Is there a way to achieve that?
Thanks in advance!

Well, then the question is how do you create the VMs inside the module and make use of nic_ids within the VM module?

Yes, thats what I am looking for… the VMs, which are created through the VM module, have to use the NIC_ID created by the NIC module.

Do you have VM module code you could share, to work on?

Sure, here it is :

resource "azurerm_linux_virtual_machine" "vm" {

  for_each = var.vms

  name                = each.value["vm_name"]
  location            = each.value["location"]
  resource_group_name = each.value["rg_name"]

  admin_username                  = each.value["admin_username"]
  admin_password                  = var.admin_password
  network_interface_ids           = var.nic_ids
  disable_password_authentication = false
  size                            = "Standard_B1s"
  os_disk {
    caching              = "ReadOnly"
    storage_account_type = "Standard_LRS"
    name                 = each.value["os_disk_name"]
    disk_size_gb         = "40"

  source_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "16.04-LTS"
    version   = "latest"

Thanks again!

You might also think about creating multiple instances of the modules instead of creating multiple resources within a single module (type).

Try using a helper map in which has the same keys as var.vms.

locals {
  nics_map = zipmap(keys(var.vms),module.nic.nic_ids)

After that pass this to the vm module in

nic_ids = local.nics_map #please note this changes the input type within the module

Within the module you can then refer using:

network_interface_ids           = [var.nic_ids[each.key]]

Thanks @tbugfinder for the suggestion.
I just wanted to be sure where I make these changes.
My VM module file is called, and my parent module that calls the VM and NIC module is called
All the changes you mentioned above, will be in ?

well, no.
I’ll change my previous post.

Thanks @tbugfinder for your continued support!
I see what you are suggesting with zipmap.
Using that, our local.nics_map will look something like this, creating a one to one relation with VMs and NIC ids:

local.nics_map = {
vm1 = “<nic-id-1>”
vm2 = “<nic-id-2>”

However, the nic_ids in refers to the network interfaces to be associated with the VM, which has to be a string, and that variable type cant be changed since its internal to Azure.

I used below, but got error:

nic_ids = tostring(values(local.nics_map))

Error: Invalid function argument
on line 52, in module “vm”:
52: nic_ids = tostring(values(local.nics_map))
| local.nics_map is object with 2 attributes
Invalid value for “v” parameter: cannot convert tuple to string.

Is there a way around?
Thanks again!

Within the VM module, above code should only get the nic_id, no?

Yes, thats right.
I am referring to the value of nic_ids, that we are passing in : (I apologize for formatting)

locals {
tags = {
env = “test”
created_by = “xxx”
nics_map = zipmap(keys(var.vms),module.nic.nic_ids)
module “nic” {
source = “
version = “0.2.4”
nics = var.nics
output “map” {
value = module.nic.map_nic_ids
output “nic_name” {
value = module.nic.nic_names
output “nic_ids” {
value = module.nic.nic_ids
module “vm” {
source = “
version = “0.1.1”
admin_password = var.admin_password
vms = var.vms
nic_ids = local.nics_map

Are you saying the variable type cannot be changed to a map here?

Are you the owner of the module source?
zipmap could also be moved into the VM module.

Yes, thats what I believe.

Yes, I am the owner of the module

I’m sorry then I don’t get your point. You shouldn’t have to mangle around with tosting(). Just use network_interface_ids = [var.nic_ids[each.key]].
each.key should map to VM1 and VM2.