"Error: Invalid count argument" error when trying to find the routing table' s id from the subnet ids to add new route entries

Hi all,

I am trying to update the routing table of the subnets in VPC A and VPC B to include route to a VPC peering end-point. This is my terraform code.

main.tf
—————

module "vpc" {
  source = "terraform-aws-modules/vpc/aws"
  version = "~> 3.14.2"
  
  for_each = local.vpc_list
  name = each.key
  cidr =each.value.vpc_cidr
  azs = each.value.vpc_azs
  public_subnets  = each.value.vpc_public_subnets
  private_subnets = each.value.vpc_private_subnets
  enable_nat_gateway = each.value.vpc_enable_nat_gateway
  enable_vpn_gateway = each.value.vpc_enable_vpn_gateway
  tags = each.value.vpc_tags
  public_subnet_tags = each.value.vpc_public_subnet_tags
  private_subnet_tags = each.value.vpc_private_subnet_tags
}


resource "aws_vpc_peering_connection" "vpc_peering_conn" {

  peer_owner_id = data.aws_caller_identity.current.account_id
  peer_vpc_id   = module.vpc["vpcB"].vpc_id
  vpc_id        = module.vpc["vpcA"].vpc_id
  auto_accept   = true

      tags = {
      Name = "VPC Peering between ${module.vpc["vpcA"].name} and 
      ${module.vpc["vpcB"].name}."
      }
}


data "aws_route_tables" "vpcA_public_subnet_rts" {
  depends_on = [ module.vpc ]
  vpc_id = module.vpc["vpcA"].vpc_id

        filter {
          name   = "tag:Subnet"
          values = ["*public*"]
        }
}

resource "aws_route" "route_vpcA" {
  count                     = length(data.aws_route_tables.vpcA_public_subnet_rts.ids)
  route_table_id            = tolist(data.aws_route_tables.vpcA_public_subnet_rts.ids)[count.index]
  destination_cidr_block    = "10.10.11.0/24"
  vpc_peering_connection_id = aws_vpc_peering_connection.vpc_peering_conn.id
}


data "aws_route_tables" "vpcB_private_subnet_rts" {
  depends_on = [ module.vpc ]
  vpc_id = module.vpc["vpcB"].vpc_id

      filter {
        name   = "tag:Subnet"
        values = ["*private*"]
      }
}

resource "aws_route" "route_vpcB" {
  count                     = length(data.aws_route_tables.vpcB_private_subnet_rts.ids)
  route_table_id            = tolist(data.aws_route_tables.vpcB_private_subnet_rts.ids)[count.index]
  destination_cidr_block    = "10.10.10.0/24"
  vpc_peering_connection_id = aws_vpc_peering_connection.vpc_peering_conn.id
}

locals.tf

locals {
   vpc_list = {
   "vpcA" = { 
       vpc_cidr = "10.10.10.0/24", 
       vpc_azs             = ["ap-southeast-1a"],
       vpc_public_subnets  = ["10.10.10.0/25"], 
       vpc_private_subnets = ["10.10.10.128/25"],
       vpc_enable_nat_gateway = false, 
       vpc_enable_vpn_gateway = false,
           vpc_tags = {
               Name= "VPC A"
               Terraform = "true"
               Environment = "1st VPC"
               Facing= "public and private"
               },
           vpc_public_subnet_tags = {
                Subnet = "vpcA_public_subnet"
                },
           vpc_private_subnet_tags = {
                Subnet = "vpcA_private_subnet"
                },
        },
   "vpcB" = {
        vpc_cidr = "10.10.11.0/24", 
        vpc_azs             = ["ap-southeast-1b"],
        vpc_public_subnets  = [],
        vpc_private_subnets = ["10.10.11.0/24"], 
        vpc_enable_nat_gateway = false, 
        vpc_enable_vpn_gateway = false,
            vpc_tags = {
               Name= "VPC B"
               Terraform = "true"
               Environment = "2nd VPC"
               Facing= "private"
               },
            vpc_public_subnet_tags = {
                Subnet = "vpcB_public_subnet"
               },
            vpc_private_subnet_tags = {
                Subnet = "vpcB_private_subnet"
               },
        },
   }
}


locals {
      routing_table = {
          route_peer_con_vpcA = {
            vpc_id = module.vpc["vpcA"].vpc_id
                route = {
                      route_peer_to_vpcB = {
                        cidr_block        = "10.10.11.0/24"
                      }  
            }
        }      
      route_peer_con_vpcB = {
        vpc_id = module.vpc["vpcB"].vpc_id
          route = {
               route_peer_to_vpcA = {
                cidr_block        = "10.10.10.0/24"
               } 
        }
    }
  }
}

When I run the terraform plan or apply I am getting the below error. Does anyone knows how to address the issue or Is there a better way to achieve what I want? Thanks.

➜  01-tf-deploy terraform apply --auto-approve
data.aws_region.current: Reading...
data.aws_caller_identity.current: Reading...
data.aws_region.current: Read complete after 0s [id=ap-southeast-1]
data.aws_ami.amzlinux2: Reading...
data.aws_ami.amzlinux2: Read complete after 1s [id=ami-0c802847a7dd848c0]
data.aws_caller_identity.current: Read complete after 1s [id=500295128231]
╷
│ Error: Invalid count argument
│
│   on main.tf line 70, in resource "aws_route" "route_vpcA":
│   70:   count                     = length(data.aws_route_tables.vpcA_public_subnet_rts.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.
╵
╷
│ Error: Invalid count argument
│
│   on main.tf line 88, in resource "aws_route" "route_vpcB":
│   88:   count                     = length(data.aws_route_tables.vpcB_private_subnet_rts.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 @ldd,

The data "aws_route_tables" "vpcA_public_subnet_rts" block in your configuration is asking Terraform to query the remote API to find out which route tables exist in this VPC, but during your initial plan the VPC doesn’t exist yet and so it’s too early to read that information. Terraform needs to know how many instances of aws_route.route_vpcA will exist before it can create a plan for that resource, and so it isn’t valid to use the number of route tables currently existing in the remote system as the basis for how many routes to create.

Instead, you will need to use the output values of the module itself in order to determine which route tables will exist. The module exports information about the route tables it is planning to create, rather than information about subnets that already exist, and so the output values can provide a suitable count value during the planning step.

This module has many different output values that contain different sets of route table IDs, and I’m not familiar enough with this module to be sure about exactly which one corresponds to what you wanted to use here, but since you were filtering by subnet names containing the substring “public” I’m going to guess that public_route_table_ids is a suitable output value to use:

resource "aws_route" "route_vpcA" {
  count = length(module.vpc.public_route_table_ids)

  route_table_id            = module.vpc.public_route_table_ids[count.index]
  destination_cidr_block    = "10.10.11.0/24"
  vpc_peering_connection_id = aws_vpc_peering_connection.vpc_peering_conn.id
}

After changing your resources to refer to the module’s outputs directly instead of the data blocks, you should remove those data blocks because they will be redundant.