Terraform: Invalid count argument

Hi All,

I am running into another issue while creating VPC and related components. Here my main.tf file

provider "aws" {
  region = var.aws_region
}


resource "aws_vpc" "mytestvpc" {
  cidr_block = "10.0.0.0/24"
  instance_tenancy = "default"
  tags = {
    "Name" = "mytest-vpc-${var.environment}"
  }
}


resource "aws_subnet" "public_subnet_2a" {
    vpc_id = "${aws_vpc.mytestvpc.id}"
    cidr_block = "10.0.0.192/26"
    availability_zone = "us-west-2a"
    tags = {
      "Name" = "public-us-west-2a"
    }
}

resource "aws_subnet" "public_subnet_2b" {
    vpc_id = "${aws_vpc.mytestvpc.id}"
    cidr_block = "10.0.0.128/26"
    availability_zone = "us-west-2b"
    tags = {
      "Name" = "public-us-west-2b"
    }
}


resource "aws_subnet" "private_subnet_2a" {
    vpc_id = "${aws_vpc.mytestvpc.id}"
    cidr_block = "10.0.0.0/26"
    availability_zone = "us-west-2a"
    tags = {
      "Name" = "private-us-west-2a"
    }
}

resource "aws_subnet" "private_subnet_2b" {
    vpc_id = "${aws_vpc.mytestvpc.id}"
    cidr_block = "10.0.0.64/26"
    availability_zone = "us-west-2b"
}




resource "aws_internet_gateway" "mytestigw" {
  vpc_id = aws_vpc.mytestvpc.id
}



resource "aws_route_table" "mytestpublic_rt" {
  vpc_id = aws_vpc.mytestvpc.id
 route = [ {
   carrier_gateway_id = null
   cidr_block = "0.0.0.0/0"
   core_network_arn = null
   destination_prefix_list_id = null
   egress_only_gateway_id = null
   gateway_id = aws_internet_gateway.mytestigw.id
   instance_id = null
   ipv6_cidr_block = null
   local_gateway_id = null
   nat_gateway_id = null
   network_interface_id = null
   transit_gateway_id = null
   vpc_endpoint_id = null
   vpc_peering_connection_id = null
 } ]
}

resource "aws_route_table" "mytestprivate_rt" {
  vpc_id = aws_vpc.mytestvpc.id
}



resource "aws_route_table_association" "public_rt_2a" {
  subnet_id      = aws_subnet.public_subnet_2a.id
  route_table_id = aws_route_table.mytestpublic_rt.id
}
resource "aws_route_table_association" "public_rt_2b" {
  subnet_id      = aws_subnet.public_subnet_2b.id
  route_table_id = aws_route_table.mytestpublic_rt.id
}

resource "aws_route_table_association" "private_rt_2a" {
  subnet_id      = aws_subnet.private_subnet_2a.id
  route_table_id = aws_route_table.mytestprivate_rt.id
}
resource "aws_route_table_association" "private_rt_2b" {
  subnet_id      = aws_subnet.private_subnet_2b.id
  route_table_id = aws_route_table.mytestprivate_rt.id
}



resource "aws_default_security_group" "default" {
vpc_id = aws_vpc.mytestvpc.id

ingress = [ {
  cidr_blocks = ["0.0.0.0/0"]
  description = "Allowed security rules"
  from_port = 22
  ipv6_cidr_blocks = []
  prefix_list_ids = []
  protocol = "tcp"
  security_groups = [ aws_vpc.mytestvpc.default_security_group_id ]
  self = false
  to_port = 22
} ]

egress = [ {
  cidr_blocks = [ "0.0.0.0/0" ]
  description = "Allow All"
  from_port = 0
  ipv6_cidr_blocks = []
  prefix_list_ids = []
  protocol = "all"
  security_groups = [ aws_vpc.mytestvpc.default_security_group_id ]
  self = false
  to_port = 0
} ]
}

resource "aws_vpc_endpoint" "aws_trasnfer_server" {
  vpc_id = aws_vpc.mytestvpc.id
  service_name = "com.amazonaws.${var.aws_region}.transfer.server"
  subnet_ids = ["${aws_subnet.public_subnet_2a.id}", "${aws_subnet.public_subnet_2b.id}"]
  security_group_ids = ["${aws_default_security_group.default.id}"]
  vpc_endpoint_type = "Interface"
}



resource "aws_eip" "subnet_eips_one" {
    depends_on = [
      aws_vpc_endpoint.aws_trasnfer_server
    ]
  count = length(aws_vpc_endpoint.aws_trasnfer_server.network_interface_ids)
  #for_each = aws_vpc_endpoint.aws_trasnfer_server.network_interface_ids
  vpc = true
}

getting below error. I have also mentioned relevent dependencies in depends_on block but still failing. Please help.

  + network_interfaces           = (known after apply)
╷
│ Error: Invalid count argument
│ 
│   on vpc/main.tf line 196, in resource "aws_eip" "subnet_eips_one":
│  196:   count = length(aws_vpc_endpoint.aws_trasnfer_server.network_interface_ids)
│ 
│ 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.

Hi @kiran.patil,

The hashicorp/aws provider seems to be reporting that it cannot predict how many elements of network_interface_ids will be present after this object has been created.

It’s been a while since I worked with VPC endpoints so I’m not 100% sure, but I think I remember that with vpc_endpoint_type = "Interface" there will always be one network interface per distinct subnet ID, because network interfaces belong to particular subnets.

If that’s true then you could perhaps make this work by using the number of subnet IDs for your count expression, instead of the number of network interfaces:

  count = length(aws_vpc_endpoint.aws_trasnfer_server.subnet_ids)

However, unfortunately I think this might not work either because subnet_ids is probably defined by the provider as being a set of strings, and your aws_subnet IDs also won’t be known during initial apply and so Terraform won’t be able to determine how many elements the set has. (It can’t prove that the two subnet IDs are different until their values are known.)

To avoid that problem you could factor out the subnet IDs into a separate value that will always have a known length during planning, like this:

locals {
  subnet_ids = tomap({
    public_subnet_2a = aws_subnet.public_subnet_2a.id
    public_subnet_2b = aws_subnet.public_subnet_2b.id
  })
}

resource "aws_vpc_endpoint" "aws_trasnfer_server" {
  vpc_id             = aws_vpc.mytestvpc.id
  service_name       = "com.amazonaws.${var.aws_region}.transfer.server"
  subnet_ids         = values(local.subnet_ids)
  security_group_ids = [aws_default_security_group.default.id]
  vpc_endpoint_type  = "Interface"
}

resource "aws_eip" "subnet_eips_one" {
  for_each = local.subnet_ids

  vpc = true
}

This last example uses for_each instead of count because local.subnet_ids is a map. The length of that map will always be known to Terraform during planning because it’s written directly in the configuration with clearly-distinct map keys. Therefore Terraform will propose to create aws_eip instances with addresses like this:

  • aws_eip.subnet_eips_one["public_subnet_2a"]
  • aws_eip.subnet_eips_one["public_subnet_2b"]

…and each one will be associated with the corresponding subnet, so you can use each.value inside the resource "aws_eip" "subnet_eips_one" to refer to the current subnet ID, if you need to.