TerraformPilot

Troubleshooting

Fix Terraform Error - Invalid count Argument

Fix the Terraform invalid count argument error when count depends on resource attributes not known until apply. Covers for_each, data sources, and targeting.

LLuca Berton2 min read

Quick Answer

#

The count value depends on a resource attribute that Terraform can't determine during plan. Replace the computed value with a variable, data source, or switch to for_each with a known set of keys.

The Error

#

When running terraform plan, you encounter:

Error: Invalid count argument
 
  on main.tf line 15, in resource "aws_instance" "worker":
  15:   count = length(aws_subnet.private[*].id)
 
The "count" value depends on resource attributes that cannot be
determined until apply, so Terraform cannot predict how many
instances will be created. To work around this, use the -target
argument to first apply only the resources that the count depends on.

You may also see the for_each variant:

Error: Invalid for_each argument
 
The "for_each" value depends on resource attributes that cannot be
determined until apply, and so Terraform cannot determine the full
set of keys that will identify the instances of this resource.

What Causes This Error

#

Terraform needs to know count and for_each values at plan time to build the dependency graph. If the value comes from a resource that doesn't exist yet, Terraform can't determine how many instances to create.

Common Triggers

#

Using output of a resource being created:

# BAD — aws_subnet.private doesn't exist yet
resource "aws_instance" "worker" {
  count     = length(aws_subnet.private[*].id)
  subnet_id = aws_subnet.private[count.index].id
}

Computed values from data sources that depend on new resources:

# BAD — data source depends on a resource being created
data "aws_subnets" "private" {
  filter {
    name   = "vpc-id"
    values = [aws_vpc.main.id]  # VPC doesn't exist yet
  }
}
 
resource "aws_instance" "worker" {
  count = length(data.aws_subnets.private.ids)
}

Dynamically computed lengths:

# BAD — output of another module not known at plan
resource "aws_route53_record" "records" {
  count = length(module.certificates.domain_validation_options)
}

How to Fix It

#

Solution 1: Use a Variable Instead of Computed Value

#

Replace the computed count with a known variable:

variable "subnet_count" {
  description = "Number of private subnets"
  type        = number
  default     = 3
}
 
resource "aws_subnet" "private" {
  count             = var.subnet_count
  vpc_id            = aws_vpc.main.id
  cidr_block        = cidrsubnet(var.vpc_cidr, 8, count.index)
  availability_zone = data.aws_availability_zones.available.names[count.index]
}
 
resource "aws_instance" "worker" {
  count     = var.subnet_count  # Known at plan time
  subnet_id = aws_subnet.private[count.index].id
}

Solution 2: Use for_each with a Static Map

#

Instead of counting dynamically, define the instances explicitly:

variable "workers" {
  type = map(object({
    instance_type = string
    subnet_index  = number
  }))
  default = {
    "worker-1" = { instance_type = "t3.micro", subnet_index = 0 }
    "worker-2" = { instance_type = "t3.micro", subnet_index = 1 }
    "worker-3" = { instance_type = "t3.small", subnet_index = 2 }
  }
}
 
resource "aws_instance" "worker" {
  for_each      = var.workers
  ami           = data.aws_ami.ubuntu.id
  instance_type = each.value.instance_type
  subnet_id     = aws_subnet.private[each.value.subnet_index].id
 
  tags = {
    Name = each.key
  }
}

Solution 3: Use a Data Source for Existing Resources

#

If the resources already exist (created outside this config), use a data source:

# GOOD — data source reads existing resources
data "aws_subnets" "private" {
  filter {
    name   = "vpc-id"
    values = [var.vpc_id]  # Known variable, not computed
  }
 
  tags = {
    Tier = "private"
  }
}
 
resource "aws_instance" "worker" {
  count     = length(data.aws_subnets.private.ids)
  subnet_id = data.aws_subnets.private.ids[count.index]
}

Solution 4: Split Into Two Applies with -target

#

When restructuring isn't practical, apply the dependency first:

# Step 1: Create the subnets
terraform apply -target=aws_subnet.private
 
# Step 2: Now count is known, apply everything
terraform apply

Note: -target is a workaround, not a best practice. Refactor your config when possible.

Solution 5: Use locals to Derive Count from Known Values

#
variable "availability_zones" {
  type    = list(string)
  default = ["us-east-1a", "us-east-1b", "us-east-1c"]
}
 
locals {
  az_count = length(var.availability_zones)
}
 
resource "aws_subnet" "private" {
  count             = local.az_count
  vpc_id            = aws_vpc.main.id
  cidr_block        = cidrsubnet(var.vpc_cidr, 8, count.index)
  availability_zone = var.availability_zones[count.index]
}
 
resource "aws_instance" "worker" {
  count     = local.az_count  # Same known value
  subnet_id = aws_subnet.private[count.index].id
}

Solution 6: Use the toset() Pattern with for_each

#

For resources that reference other resource outputs:

variable "subnet_cidrs" {
  type    = set(string)
  default = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
}
 
resource "aws_subnet" "private" {
  for_each          = var.subnet_cidrs
  vpc_id            = aws_vpc.main.id
  cidr_block        = each.value
}
 
resource "aws_instance" "worker" {
  for_each      = var.subnet_cidrs  # Same static set
  subnet_id     = aws_subnet.private[each.key].id
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t3.micro"
}

Common Patterns That Trigger This Error

#
PatternWhy It FailsFix
count = length(aws_resource.x[*].id)Resource doesn't exist yetUse a variable for count
for_each = toset(aws_resource.x[*].name)Set not known at planUse a static variable set
count = data.source.x.count where data depends on new resourceData source can't evaluateUse pre-existing data or variable
count = module.x.output_countModule output computed at applyPass the count as input to both modules

Troubleshooting Checklist

#
  1. ✅ Does the count or for_each value depend on a resource being created in the same apply?
  2. ✅ Can you replace it with a variable or local that's known at plan time?
  3. ✅ Are you using a data source that depends on a new resource?
  4. ✅ Can you split into two applies as a temporary fix?
  5. ✅ Would for_each with a static map work better than count?

Prevention Tips

#
  • Use variables for counts — never derive count from resource attributes in the same config
  • Prefer for_each over countfor_each with known keys is more stable and doesn't reorder on changes
  • Plan before refactoring — run terraform plan after changes to catch this early
  • Design modules with known inputs — pass counts/keys as input variables, not as computed outputs
#

Conclusion

#

This error protects you from unpredictable infrastructure changes. Terraform needs to know exactly how many resources to create before it starts. Restructure your config so count and for_each use known values — variables, locals, or data sources that don't depend on resources being created in the same apply.

#count#depends-on#apply

Share this article