Eddie's Blog

Thoughts, DIY, projects, Linux, IaC, and other things.

Index out of range in terrafrom

Accidently nuked half of some resources and broke DNS (yes, it is in fact always DNS). One of the first things I learned and is on a lot of guides for terraform is how count works. It’s one of the meta-arguments you can use with most resources, others are

depends_on
count
for_each
provider / providers
lifecycle

Here’s an example for count before I show my oops.

variable "names" {
  default = ["alice", "bob", "carol"]
}

resource "aws_instance" "web" {
  count         = length(var.names)
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"

  tags = {
    Name = var.names[count.index]
  }
}

Remove "bob" → default = ["alice", "carol"]. You’ll see this in your terraform run of web[1] transitioning.

  ~ Name = "bob" -> "carol"

carol shifts from index 2 → 1, so Terraform modifies the bob instance to become carol, and destroys the old carol. Two changes instead of one.

count is very quick and easy to use but honestly I avoided it. If I read of a feature that has to be used with extra considerations, I’d rather use the pattern that doesn’t let me screw up if my coffee has fully kicked in.


In my case, I added to middle of an array in a variable but the implementation logic was a count instead of a for_each.

Here’s an implementation that guarentess uniqness in the array to avoid collisions and doesn’t care about order.

# Before (vulnerable — index shuffle on any list change)
resource "aws_instance" "web" {
  count         = length(var.names)
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"

  tags = {
    Name = var.names[count.index]
  }
}

# After (safe — each instance is an independent resource)
resource "aws_instance" "web" {
  for_each      = toset(var.instances)
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"

  tags = {
    Name = each.key
  }
}

Even better is that with the first method you access the resource like aws_instance.web[0] but with the 2nd you get a much more descriptive and assuring aws_instance.web["bob"]

⬅ Previous post
DND One Shot Recommendations

Next post ➡
TIL