The given value is not suitable for module

I am trying to define a list of hosts that I will for_each over but for now I am just trying to get a simple plan to work for the the module and variable.

main.tf

module "the_hosts" {
  source = "./hosts"
  systems = [{
    hostname                 = "host01",
    interface =  {
    leafs =  [{ 
    device = "en0"
    ip       = "1.2.3.4"
    netmask  = "/24"
    gateway  = "10.X.X.1"
    },
    {device    = "en3"
      ip       = "2.3.4.5"
      netmask  = "/24"
      gateway  = "10.X.X.1"
    }]
    } 
}, 
{
    hostname                 = "host-02",
    interface =  {
    leafs =  [{ 
    device = "en0"
    ip       = "1.2.3.4"
    netmask  = "/24"
    gateway  = "10.X.X.1"
    },
    {device    = "en3"
      ip       = "2.3.4.5"
      netmask  = "/24"
      gateway  = "10.X.X.1"
    }]
    } 
}
  ]
}

./hosts/variables.tf

variable "systems" {
  type = list(object({
    hostname                 = string,
    interface = map(object({
      leafs = list(map(string))
    }))
  }))
}

./hosts/main.tf

locals {
  # flatten ensures that this local value is a flat list of objects, rather
  # than a list of lists of objects.
  systems = flatten([
    for system_key, system in var.systems : [
      { hostname = system.hostname }
    ]
  ])
}


resource "null_resource" "systems" {
  for_each = { for system in local.systems : system.hostname => system }
  triggers = {
    name = each.value.hostname
  }
}

terraform plan throws

The given value is not suitable for module.the_hosts.var.systems declared at hosts/variables.tf:1,1-19: element 0: attribute "interface": element "leafs": object required.

I have assigned values to systems.interface.leafs in my module “the_hosts”. Anyone any idea what is wrong here?

Hi @terrag,

Your type constraint says that “interface” is a map of objects, but the value you assigned is just a single object.

Since you chose a singular name for that attribute I assume you intended a single object, in which case you can remove the map(...) constraint and just use the object constraint inside directly, which will declare that “interface” is a single object of the given type.

Thanks @apparentlymart though I do intend for interface to contain a map of objects. I would expect the code to work whether the map contains one object like it does now whilst I test this code or whether it contains multiple objects later. It makes sense to rename to “interfaces” for readability.

FWIW out of curiosity I just now tested by removing map

variable "systems" {
  type = list(object({
    hostname                 = string,
    interface = object({
      leafs = list(map(string))
    })
  }))
}

Terraform plan still get

The given value is not suitable for module.the_hosts.var.systems declared at hosts/variables.tf:1,1-19: element 0: attribute "interface": element "leafs": object required.

I think you must have not saved the file after editing then, because if I copy/paste the relevant snippets into files, and run Terraform locally, it is happy with this change.

Thanks @maxb. Yip I had not saved the file in another tmux pane. Ultimately I want to flatten my complex variable so I can for_each over it. I am gradually building up to create the complex variable before I even try to flatten it.

main.tf

module "the_hosts" {
  source = "./hosts"
  systems = [{
    hostname                 = "host01",
    interfaces =  {
    leafs =  [{ 
    device = "en0"
    ip       = "1.2.3.4"
    netmask  = "/24"
    gateway  = "10.X.X.1"
    },
    {device    = "en3"
      ip       = "2.3.4.5"
      netmask  = "/24"
      gateway  = "10.X.X.1"
    }],
    another_map = {
       label1 = "hello"
       label2 = "Goodbye" 
    } 
    } 
}, 
{
    hostname                 = "host-02",
    interfaces =  {
    leafs =  [{ 
    device = "en0"
    ip       = "1.2.3.4"
    netmask  = "/24"
    gateway  = "10.X.X.1"
    },
    {device    = "en3"
      ip       = "2.3.4.5"
      netmask  = "/24"
      gateway  = "10.X.X.1"
    }],
    another_map = {
       label1 = "hello"
       label2 = "Goodbye" 
    } 
    }
}
]}

hosts/variables.tf

variable "systems" {
  type = list(object({
    hostname                 = string,
    interfaces = map(object({
      leafs = list(map(string)),
      another_map = map(string)
    }))
  }))
}

Now get

An argument definition must end with a newline.

Very intuitve.

I must say I find Terraform awkward for anything other than simple resources.

It’s actually objecting to this:

on the final line of main.tf.

You need a newline between these two characters.

Which is admittedly a fairly strange property of HCL.

You might get on better with it though, if your formatting/indentation was a bit more consistent. You can run terraform fmt with various options to auto-format Terraform code. I highly recommend hooking it up to a keybinding you can invoke from your editor of choice.

Thanks @maxb, I fixed line thing.

Now I am back to

The given value is not suitable for module.the_hosts.var.systems declared at hosts/variables.tf:1,1-19: element 0: attribute "interfaces": element "another_map": attributes
│ "another_map" and "leafs" are required.

Love Terraform. It is so intuitive :frowning:

Hi @terrag,

I understand that you are getting frustrated here but let’s look more closely at what this error message is saying:

The given value is not suitable for module.the_hosts.var.systems declared at hosts/variables.tf:1,1-19: element 0: attribute “interfaces”: element “another_map”: attributes “another_map” and “leafs” are required.

This error message is telling you which part of the value you assigned to this variable is invalid, and what is invalid about it.

I’m going to format your example so we can see the data structure more clearly, since I think that is part of what’s making it hard to correlate the value you’ve provided with the error message:

module "the_hosts" {
  source = "./hosts"
  systems = [
    {
      hostname = "host01",
      interfaces = {
        leafs = [
          {
            device  = "en0"
            ip      = "1.2.3.4"
            netmask = "/24"
            gateway = "10.X.X.1"
          },
          {
            device  = "en3"
            ip      = "2.3.4.5"
            netmask = "/24"
            gateway = "10.X.X.1"
          },
        ],
        another_map = {
          label1 = "hello"
          label2 = "Goodbye"
        }
      }
    },
    {
      hostname = "host-02",
      interfaces = {
        leafs = [
          {
            device  = "en0"
            ip      = "1.2.3.4"
            netmask = "/24"
            gateway = "10.X.X.1"
          },
          {
            device  = "en3"
            ip      = "2.3.4.5"
            netmask = "/24"
            gateway = "10.X.X.1"
          },
        ],
        another_map = {
          label1 = "hello"
          label2 = "Goodbye"
        }
      }
    },
  ]
}

The error message is describing the traversal path var.systems[0].interfaces["another_map"], and reporting that it doesn’t contain the attributes another_map and leafs that you declared in your type constraint. Here’s the part of the data structure the error message is talking about:

        another_map = {
          label1 = "hello"
          label2 = "Goodbye"
        }

Indeed, this object has attributes label1 and label2, which doesn’t match the type constraint. Terraform is treating another_map as the key of an element in the map of objects you declared, and so it expects the value to be the corresponding object. But you’ve set interfaces to just be a single object rather than a map of objects, so Terraform finds your another_map value here instead.

At this point I feel unsure about whether you want to change the type constraint to match the value or to change the value to match the type constraint, so I’ll explore both separately but you should choose only one of the following sections to follow, because they are mutually-exclusive.


I think the following type constraint would match the data structure you’ve written out here, assuming I’m understanding correctly your intent about which of these mappings are intended to be fixed object types and which are intended to be arbitrary maps:

variable "systems" {
  type = list(
    object({
      hostname   = string
      interfaces = object({
        device  = string
        ip      = string
        netmask = string
        gateway = string
      })
      another_map = map(string)
    })
  )
}

In particular, I’ve assumed that you intended label1 and label2 in your another_map attributes to be arbitrary keys chosen by the caller, and that they only happened to match between the two examples because they are contrived examples.

I also once again removed the map(...) in your definition of interfaces, because your example values for that attribute are both just single objects rather than maps of objects.


Alternatively, here’s my attempt at writing a value that matches your type constraint, although of course I have to make some guesses here about what you intended each of the parts of the type constraint to mean because I’m not familiar with the domain model you’re representing here:

module "the_hosts" {
  source = "./hosts"
  systems = [
    {
      hostname = "host01",
      interfaces = {
        interface1 = {
          leafs = [
            {
              device  = "en0"
              ip      = "1.2.3.4"
              netmask = "/24"
              gateway = "10.X.X.1"
            },
            {
              device  = "en3"
              ip      = "2.3.4.5"
              netmask = "/24"
              gateway = "10.X.X.1"
            },
          ],
          another_map = {
            label1 = "hello"
            label2 = "Goodbye"
          }
        }
        interface2 = {
          leafs = [
            {
              device  = "en0"
              ip      = "1.2.3.4"
              netmask = "/24"
              gateway = "10.X.X.1"
            },
            {
              device  = "en3"
              ip      = "2.3.4.5"
              netmask = "/24"
              gateway = "10.X.X.1"
            },
          ],
          another_map = {
            label1 = "hello"
            label2 = "Goodbye"
          }
        }
      }
    },
    {
      hostname = "host-02",
      interfaces = {
        interface3 = {
          leafs = [
            {
              device  = "en0"
              ip      = "1.2.3.4"
              netmask = "/24"
              gateway = "10.X.X.1"
            },
            {
              device  = "en3"
              ip      = "2.3.4.5"
              netmask = "/24"
              gateway = "10.X.X.1"
            },
          ],
          another_map = {
            label1 = "hello"
            label2 = "Goodbye"
          }
        }
      }
    },
  ]
}

Notice that in this example under each interfaces attribute there’s an extra mapping level defining elements with the keys interface1 and interface2 for the first host, and interface3 for the second host. This matches the constraint you specified for interfaces, where you requested a map of objects: the interface1 and interface2 are the keys of the elements of that map, and the associated objects are the corresponding values.

Thank you @apparentlymart. I will continue my attempts to get my simple contrived example to work. It might help if I provide some context. For every system I will define multiple interfaces like the following. I would like to iterate (for_each) each system and create various resources from the values. There are always more than two systems but the following just illustrates that there are more than one. Ultimately I will have to flatten this because for_each is unable to iterate over this shape :frowning: Right now I am just trying to define the type and test that it is correct using null_resource before I move on to flattening this. The final resources will all be keyed on hostname. I am not sure yet if Terraform can handle my use case but will see.

module "the_hosts" {
  source = "./hosts"
  systems = [
    {
      hostname = "host01”,
      interfaces =  {
        leafs =  [{ 
         device = "en0"
          ip       = "10.X.X.X"
          netmask  = "/24"
          gateway  = "10.X.X.X"
        },
        { device = "en1"
          ip       = "10.X.X.X"
          netmask  = "/24"
          gateway  = "10.X.X.X"
        }],
        lom = { ip = "X.X.X.X" },      
        management = {                
          device = "en3"              
          ip        = "X.X.X.X"       
          netmask   = "/24"
          gateway   = "X.X.X.X"
          mac       = "aa:bb:cc:dd:ee:ff" 
        },
        stable = {
          device = "lo"     
          ip     = "X.X.X.X"
        }
      },
      disks = ["sda", "sdb"]
	},
    {
      hostname = "host02”,
      interfaces =  {
        leafs =  [{ 
          device = "en0"
          ip       = "10.X.X.X"
          netmask  = "/24"
          gateway  = "10.X.X.X"
        },
        { device = "en1"
          ip       = "10.X.X.X"
          netmask  = "/24"
          gateway  = "10.X.X.X"
        }],
        lom = { ip = "X.X.X.X" },      
        management = {                
          device = "en3"              
          ip        = "X.X.X.X"       
          netmask   = "/24"
          gateway   = "X.X.X.X"
          mac       = "aa:bb:cc:dd:ee:00" 
        },
        stable = {
          device = "lo"     
          ip     = "X.X.X.X"
        }
      },
      disks = ["sda", "sdb"]
	}    
}

If you are intending to use the hostname of each system as the unique tracking key anyway then it will probably be easiest to make your top-level collection be a map of objects where the keys are hostnames, rather than a list where one of the attributes is a unique key. Along with already being shaped in the way that for_each will expect, this can also help communicate to the user of your module that the hostnames are the tracking keys and must therefore be unique across all elements.

You are right that if you need to declare some resources “for each interface of each system” then this will require a flattening step inside your module, to create a single map with all of the interfaces together and keys that include both the hostname and the interface key. I expect that this will closely resemble the pattern shown in the documentation of the flatten function, but if course if that doesn’t work out then we can discuss here what makes your case different and find a working solution; I don’t yet see any reason why what you want to do should not be possible.

Thanks again @apparentlymart. I like idea to use a map with hostname as the key. That seems more natural. Anyway, I am going to hand this on to someone else to see can they define the schema for this. I am getting nowhere fast with this :frowning: If we get it working I will update.

@apparentlymart one quick question if I may. I appreciate your input. I think the schema should look like the following (hostname removed as will use map now keyed on hostname) but terraform fmt throws

A comma is required to separate each function argument from the next.

It is not jumping out at me where the missing comma should go.

variable systems {

type = map(object(
 {
      interfaces =  map(object(
      {
        leafs =  list(object(
          {
          device = string
          ip       = string
          netmask  = string
          gateway  = string
         }
        )),
        lom = { ip = string },
        management = {
          device = string
          ip        = string
          netmask   = string
          gateway   = string
          mac       = string
        },
        stable = {
          device = string
          ip     = string
        }
      }
      )
      ),
      disks = list(string)
  }
)

}

Hi @terrag,

When I tried what you shared, I saw Terraform produce a few different error messages, including the one you mentioned:

╷
│ Error: Invalid type specification
│ 
│   on unsuitable-value.tf line 15, in variable "systems":
│   15:         lom = { ip = string },
│ 
│ A type specification is either a primitive type keyword (bool, number, string) or a complex type constructor call, like list(string).
╵
╷
│ Error: Invalid type specification
│ 
│   on unsuitable-value.tf line 16, in variable "systems":
│   16:         management = {
│   17:           device = string
│   18:           ip        = string
│   19:           netmask   = string
│   20:           gateway   = string
│   21:           mac       = string
│   22:         },
│ 
│ A type specification is either a primitive type keyword (bool, number, string) or a complex type constructor call, like list(string).
╵
╷
│ Error: Invalid type specification
│ 
│   on unsuitable-value.tf line 23, in variable "systems":
│   23:         stable = {
│   24:           device = string
│   25:           ip     = string
│   26:         }
│ 
│ A type specification is either a primitive type keyword (bool, number, string) or a complex type constructor call, like list(string).
╵
╷
│ Error: Missing argument separator
│ 
│   on unsuitable-value.tf line 34, in variable "systems":
│    3: type = map(object(
│    4:  {
│    5:       interfaces =  map(object(
│    6:       {
│    7:         leafs =  list(object(
│    8:           {
│    9:           device = string
│   10:           ip       = string
│   11:           netmask  = string
│   12:           gateway  = string
│   13:          }
│   14:         )),
│   15:         lom = { ip = string },
│   16:         management = {
│   17:           device = string
│   18:           ip        = string
│   19:           netmask   = string
│   20:           gateway   = string
│   21:           mac       = string
│   22:         },
│   23:         stable = {
│   24:           device = string
│   25:           ip     = string
│   26:         }
│   27:       }
│   28:       )
│   29:       ),
│   30:       disks = list(string)
│   31:   }
│   32: )
│   33: }
│ 
│ A comma is required to separate each function argument from the next.
╵

Unfortunately when there are syntax errors Terraform can only make a best effort to guess what you were trying to achieve and so the error messages can sometimes be confusing or misleading – in a sense, Terraform itself is “confused”, so its explanation of the problem doesn’t always make sense.

So I copied the text into my test editor and added newlines and indentations manually in all of the places I’d typically put them when following idiomatic style, which led met to this:

variable systems {
  type = map(
    object({
      interfaces = map(
        object({
          leafs =  list(
            object({
              device = string
              ip       = string
              netmask  = string
              gateway  = string
            })
          ),
        ),
        lom = {
          ip = string
        },
        management = {
          device  = string
          ip      = string
          netmask = string
          gateway = string
          mac     = string
        },
        stable = {
          device = string
          ip     = string
        }
      })
    ),
    disks = list(string)
  })
}

Although I can’t show it this way in the forum, my editor highlights the parenthesis at the end of type = map( as not having a closing ), which led me to notice that your final attribute disks is not nested inside the object({ ... }) declaration, but Terraform didn’t notice that correctly because the closing ) for map( is incorrectly written as }) instead, which confused both Terraform and my human eyes when trying to spot the problem just from reading the input.

The same problem seems to be true for the nested interfaces map of objects too, which I think was a few too many syntax errors for the Terraform parser’s recovery behavior to be able to figure out, and so it just reported whatever it parsed next as being an error.

With all of that said then, I’ve tried to rework this to match what I think you were intending to write, and terraform fmt now accepts it:

variable "systems" {
  type = map(
    object({
      interfaces = map(
        object({
          leafs = list(
            object({
              device  = string
              ip      = string
              netmask = string
              gateway = string
            })
          )
          lom = {
            ip = string
          }
          management = {
            device  = string
            ip      = string
            netmask = string
            gateway = string
            mac     = string
          }
          stable = {
            device = string
            ip     = string
          }
        })
      )
      disks = list(string)
    })
  )
}

Again, because I don’t know about the domain model you are trying to represent here I had to guess which of the attributes belong to “leafs”, which to “interfaces”, and which to whole “systems”, but hopefully I got this close enough that you can see how to move around the individual attribute definitions into different object types if you need to.

You’ll probably also notice that I adopted a style here where each type constraint or attribute value is on a line of its own, and so I represented lists of object types like this:

map(
  object({
    # ...
  })
)

…instead of like this:

map(object({
  # ...
}))

Both of these are reasonable idiomatic style, and I would often use the second compact form for relatively simple type constraints, but I chose to reflect the nesting more directly in the indentation here just because this is a pretty complicated type constraint and combining the collection type and the object type into a single line – and therefore having to do the same for the closing delimiters })), was making this harder rather than easier to read.

For completeness though, here’s the more vertically-compact form of the same type constraint:

variable "systems" {
  type = map(object({
    interfaces = map(object({
      leafs = list(object({
        device  = string
        ip      = string
        netmask = string
        gateway = string
      }))
      lom = {
        ip = string
      }
      management = {
        device  = string
        ip      = string
        netmask = string
        gateway = string
        mac     = string
      }
      stable = {
        device = string
        ip     = string
      }
    }))
    disks = list(string)
  }))
}

It’s tough to say objectively which of these is “better” in this case. I find the second example less readable because it’s harder to visually separate the collection wrapper map or list from the object type inside it, but of course that’s just how my brain prefers to work, and you might have different preferences. I would not recommend trying to be any more compact than the most recent example above though.

Thankyou @apparentlymart. I will have a look at this and see if I can make progress. What is your test editor? Is it an internal tool or something in the public domain?

I’m using Visual Studio Code with the Terraform extension installed. The specific feature that allowed me to see the parenthesis nesting error was that Visual Studio Code can natively count bracket nesting for a language that has defined “brackets”, and the Terraform extension includes a definition of brackets in the Terraform language:

I don’t really like to share screenshots because they aren’t accessible to folks who can’t see, but I don’t really know how else to illustrate this entirely-visual behavior to you, so I’ll make an exception here and apologize in advance to any future reader who cannot see these images.

Here’s how it looked with the valid example I still had open in my editor from when I was preparing my previous answer:

The purple, blue, and yellow highlighting on the brackets aims to illustrate how they are nested, to make it easier to scan. I don’t personally find that presentation particularly intuitive and so I honestly usually ignore it, but the more interesting case is when I intentionally reintroduce an error similar to the one we were discussing earlier:

In this version, some of the brackets are highlighted in red to indicate that they don’t have matching pairs. This isn’t exactly the same as the incorrect example you shared earlier, but that red parenthesis after the first map is what I was referring to that helped me notice that this was a bracket nesting problem rather than some other kind of problem.

Amusingly, taking and staring at these screenshots some hours later made me realize that what I shared with you wasn’t actually valid, because lom, management, and stable are all missing explicit type constraints and are written instead as if they were object values.

Sorry about that! Sometimes when I’m quickly editing these examples I miss things because I’m diverting my attention to and from other work. I think the following is a valid version of the above, with those attributes now properly marked as having object type constraints:

variable "systems" {
  type = map(object({
    interfaces = map(object({
      leafs = list(object({
        device  = string
        ip      = string
        netmask = string
        gateway = string
      }))
      lom = object({
        ip = string
      })
      management = object({
        device  = string
        ip      = string
        netmask = string
        gateway = string
        mac     = string
      })
      stable = object({
        device = string
        ip     = string
      })
    }))
    disks = list(string)
  }))
}

Thank you and yes I noticed that when I tried to run terraform plan. One step at a time. Now all I need to fix is

The given value is not suitable for module.the_hosts.var.systems declared at hosts/variables.tf:1,1-19: element “host01”: attribute “interfaces”: element “leafs”:

then if I run terraform plan again I get

The given value is not suitable for module.the_hosts.var.systems declared at hosts/variables.tf:1,1-19: element “host01”: attribute “interfaces”: element “stable”:
│ attributes “leafs”, “lom”, “management”, and “stable” are required.

I had expected this to be relatively simple but it appears not to be.

I am starting to suspect that terraform is having trouble with nested objects. maybe a bit like Random (and incorrect) error messages when validating "nested object" variables. · Issue #27010 · hashicorp/terraform · GitHub

I am on terraform v1.2.5

Hi @terrag,

Can you share the latest configuration you are using, including both the variable declaration and the value you’re assigning to the variable?

All I have is the following. I have removed the main.tf that was in hosts directory. I run terraform console to get the error.

main.tf

module "the_hosts" {
  source = "./hosts"
  systems =  {
      host01 = {
      interfaces =  {
        leafs =  [{
          device = "en0"
          ip       = "10.X.X.X"
          netmask  = "/24"
          gateway  = "10.X.X.X"
        },
        { device = "en1"
          ip       = "10.X.X.X"
          netmask  = "/24"
          gateway  = "10.X.X.X"
        }],
        lom = { ip = "X.X.X.X" },
        management = {
          device = "en3"
          ip        = "X.X.X.X"
          netmask   = "/24"
          gateway   = "X.X.X.X"
          mac       = "aa:bb:cc:dd:ee:ff"
        },
        stable = {
          device = "lo"
          ip     = "X.X.X.X"
        }
      },
      disks = ["sda", "sdb"]
    },
      host02 = {
      interfaces =  {
        leafs =  [{
          device = "en0"
          ip       = "10.X.X.X"
          netmask  = "/24"
          gateway  = "10.X.X.X"
        },
        { device = "en1"
          ip       = "10.X.X.X"
          netmask  = "/24"
          gateway  = "10.X.X.X"
        }],
        lom = { ip = "X.X.X.X" },
        management = {
          device = "en3"
          ip        = "X.X.X.X"
          netmask   = "/24"
          gateway   = "X.X.X.X"
          mac       = "aa:bb:cc:dd:ee:00"
        },
        stable = {
          device = "lo"
          ip     = "X.X.X.X"
        }
      },
      disks = ["sda", "sdb"]
    }
}
}

hosts/variables.tf

variable "systems" {
  type = map(object({
    interfaces = map(object({
      leafs = list(object({
        device  = string
        ip      = string
        netmask = string
        gateway = string
      }))
      lom = object({
        ip = string
      })
      management = object({
        device  = string
        ip      = string
        netmask = string
        gateway = string
        mac     = string
      })
      stable = object({
        device = string
        ip     = string
      })
    }))
    disks = list(string)
  }))
}

When I try this configuration on my system I get the following error message, which is a little different than the one you shared above:

╷
│ Error: Invalid value for input variable
│ 
│   on unsuitable-value.tf line 3, in module "the_hosts":
│    3:   systems = {
│    4:     host01 = {
│    5:       interfaces = {
│    6:         leafs = [
│    7:           {
│    8:             device  = "en0"
│    9:             ip      = "10.X.X.X"
│   10:             netmask = "/24"
│   11:             gateway = "10.X.X.X"
│   12:           },
│   13:           { device  = "en1"
│   14:             ip      = "10.X.X.X"
│   15:             netmask = "/24"
│   16:             gateway = "10.X.X.X"
│   17:           }
│   18:         ],
│   19:         lom = { ip = "X.X.X.X" },
│   20:         management = {
│   21:           device  = "en3"
│   22:           ip      = "X.X.X.X"
│   23:           netmask = "/24"
│   24:           gateway = "X.X.X.X"
│   25:           mac     = "aa:bb:cc:dd:ee:ff"
│   26:         },
│   27:         stable = {
│   28:           device = "lo"
│   29:           ip     = "X.X.X.X"
│   30:         }
│   31:       },
│   32:       disks = ["sda", "sdb"]
│   33:     },
│   34:     host02 = {
│   35:       interfaces = {
│   36:         leafs = [
│   37:           {
│   38:             device  = "en0"
│   39:             ip      = "10.X.X.X"
│   40:             netmask = "/24"
│   41:             gateway = "10.X.X.X"
│   42:           },
│   43:           { device  = "en1"
│   44:             ip      = "10.X.X.X"
│   45:             netmask = "/24"
│   46:             gateway = "10.X.X.X"
│   47:           }
│   48:         ],
│   49:         lom = { ip = "X.X.X.X" },
│   50:         management = {
│   51:           device  = "en3"
│   52:           ip      = "X.X.X.X"
│   53:           netmask = "/24"
│   54:           gateway = "X.X.X.X"
│   55:           mac     = "aa:bb:cc:dd:ee:00"
│   56:         },
│   57:         stable = {
│   58:           device = "lo"
│   59:           ip     = "X.X.X.X"
│   60:         }
│   61:       },
│   62:       disks = ["sda", "sdb"]
│   63:     }
│   64:   }
│ 
│ The given value is not suitable for module.the_hosts.var.systems declared at
│ child/unsuitable-value-child.tf:1,1-19: element "host01": attribute
│ "interfaces": element "stable": attributes "leafs", "lom", "management", and
│ "stable" are required.
╵

It seems like on our previous rounds I’ve diagnosed a problem and then we’ve later found that the configuration you shared didn’t exactly match the one you ran, and so we ended up with a different error again.

Can we try to make sure we’re both running exactly the same configuration and getting exactly the same error first, and then I can try to explain what the error means? Specifically, I’d like you to try running exactly the configuration you shared in your previous comment and show me the full error message Terraform produced, so we can see how it differs (if at all) from what it’s doing on my system.