The InvalidSubnet.Range error occurs when your Terraform subnet CIDR block is invalid or doesn't fit within your VPC's IP address space. This typically happens when the subnet CIDR is outside the VPC range, overlaps with existing subnets, or when using secondary CIDR blocks before they're fully associated.
When creating an AWS subnet with Terraform, the subnet's CIDR block must be a valid subset of the VPC's CIDR block. The InvalidSubnet.Range error indicates that the CIDR block you're trying to assign to your subnet violates AWS subnet requirements. This error commonly occurs when: - The subnet CIDR is completely outside the VPC's address range (e.g., VPC is 10.0.0.0/16 but subnet is 172.16.0.0/24) - The subnet size is too large (subnets must be at least /28) or uses invalid boundaries - Multiple subnets overlap with each other - Using secondary VPC CIDR blocks before they're fully provisioned - IPv6 CIDR block issues when enabling IPv6 on subnets AWS maintains strict validation to prevent IP address exhaustion and routing conflicts within your VPC.
First, confirm the CIDR range of your VPC and the subnet you're trying to create:
# View your Terraform state or configuration
terraform state show aws_vpc.main
terraform state show aws_subnet.example
# Or check directly in AWS
aws ec2 describe-vpcs --query 'Vpcs[*].[VpcId,CidrBlock]' --output tableIn your Terraform code, verify the VPC CIDR block:
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16" # Your VPC range
}
resource "aws_subnet" "example" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24" # Must be within 10.0.0.0/16
}The subnet CIDR block must be entirely within the VPC's range. Common private IP ranges are:
- 10.0.0.0/8 (10.0.0.0 to 10.255.255.255)
- 172.16.0.0/12 (172.16.0.0 to 172.31.255.255)
- 192.168.0.0/16 (192.168.0.0 to 192.168.255.255)
List all subnets in your VPC to identify overlaps:
aws ec2 describe-subnets --filters "Name=vpc-id,Values=vpc-xxxxx" \
--query 'Subnets[*].[SubnetId,CidrBlock,AvailabilityZone]' --output tableOr in Terraform, check your state file:
terraform state list | grep aws_subnet
terraform state show aws_subnet.subnet1
terraform state show aws_subnet.subnet2Subnets cannot overlap. For example, if you have:
- Subnet A: 10.0.1.0/24 (10.0.1.0 to 10.0.1.255)
- Subnet B: 10.0.1.128/25 (10.0.1.128 to 10.0.1.255) ← OVERLAPS!
You need to use non-overlapping ranges:
- Subnet A: 10.0.1.0/24
- Subnet B: 10.0.2.0/24
Use Terraform's cidrsubnet() function to automatically calculate non-overlapping subnets:
# Define VPC with /16 CIDR block
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
# Create subnets safely using cidrsubnet
resource "aws_subnet" "public_1" {
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 2, 0) # 10.0.0.0/18
availability_zone = "us-east-1a"
}
resource "aws_subnet" "public_2" {
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 2, 1) # 10.0.64.0/18
availability_zone = "us-east-1b"
}
resource "aws_subnet" "private_1" {
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 2, 2) # 10.0.128.0/18
availability_zone = "us-east-1a"
}The cidrsubnet() function signature: cidrsubnet(prefix, newbits, netnum)
- prefix: VPC CIDR block (e.g., "10.0.0.0/16")
- newbits: Number of bits to add to subnet mask (e.g., 2 = /18)
- netnum: Subnet number (0, 1, 2...)
This automatically prevents overlaps!
Important: If you get "not enough remaining address space", adjust newbits downward:
# If this fails with too many subnets:
cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 8, count.index) # /24
# Try a larger block size:
cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 4, count.index) # /20If you're using secondary CIDR blocks, Terraform may try to create subnets before the CIDR association is complete.
Problem scenario:
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
resource "aws_vpc_ipv4_cidr_block_association" "secondary" {
vpc_id = aws_vpc.main.id
cidr_block = "10.2.0.0/16"
}
# Error: Secondary CIDR not ready yet!
resource "aws_subnet" "secondary_subnet" {
vpc_id = aws_vpc.main.id
cidr_block = "10.2.0.0/24"
}Solution: Add explicit dependency
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
resource "aws_vpc_ipv4_cidr_block_association" "secondary" {
vpc_id = aws_vpc.main.id
cidr_block = "10.2.0.0/16"
}
# Explicitly depend on secondary CIDR association
resource "aws_subnet" "secondary_subnet" {
vpc_id = aws_vpc.main.id
cidr_block = "10.2.0.0/24"
depends_on = [aws_vpc_ipv4_cidr_block_association.secondary]
}If you still get errors after adding depends_on, run terraform twice:
# First apply: Creates VPC and associates secondary CIDR
terraform apply
# Second apply: Creates subnets once CIDR is fully ready
terraform applyUse terraform plan to validate before applying:
terraform plan -out=tfplanReview the plan output for:
- Subnet CIDR blocks make sense
- No obvious overlaps (review all subnets in the plan)
- Correct VPC associations
You can also manually verify CIDR blocks with an online CIDR calculator or test in your AWS console first:
# Use AWS CLI to validate
aws ec2 describe-vpcs --vpc-ids vpc-12345678 \
--query 'Vpcs[0].[CidrBlock,Ipv6CidrBlockAssociationSet]'If unsure about your CIDR math, write it out:
- VPC: 10.0.0.0/16 = 10.0.0.0 to 10.0.255.255 (65,536 IPs)
- Subnet /24 = 256 IPs per subnet
- Valid subnets: 10.0.0.0/24, 10.0.1.0/24, ..., 10.0.255.0/24
Common CIDR syntax errors that trigger InvalidSubnet.Range:
Correct format:
cidr_block = "10.0.1.0/24" # CORRECTCommon mistakes:
# Missing leading zeros
cidr_block = "10.0.1.0/024" # WRONG (invalid prefix)
# Wrong notation
cidr_block = "10.0.1.0-10.0.1.255" # WRONG (use CIDR notation)
# Subnet with host bits set
cidr_block = "10.0.1.128/25"
# This is 10.0.1.128 to 10.0.1.255, but the /25 prefix expects the network
# to end at a /25 boundary. Use 10.0.1.0/25 or 10.0.1.128/25 correctly.
# Using public IP ranges for private subnets
cidr_block = "8.8.8.0/24" # Public range - won't work for private VPCFixing variable interpolation issues:
# BAD: May cause validation errors during planning
variable "subnet_cidr" {
type = string
}
resource "aws_subnet" "bad" {
vpc_id = aws_vpc.main.id
cidr_block = var.subnet_cidr # Terraform can't validate before applying
}
# GOOD: Validate with Terraform functions
resource "aws_subnet" "good" {
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 2, var.subnet_index)
}IPv6 errors require specific handling:
# Step 1: Enable IPv6 on VPC
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
assign_ipv6_cidr_block = true
}
# Step 2: Wait for IPv6 CIDR association
resource "aws_vpc_ipv6_cidr_block_association" "main" {
vpc_id = aws_vpc.main.id
amazon_provided_ipv6_cidr_block = true
}
# Step 3: Create subnet with IPv6
resource "aws_subnet" "example" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
# IPv6 CIDR block from VPC
ipv6_cidr_block = cidrsubnet(aws_vpc.main.ipv6_cidr_block, 8, 1)
assign_ipv6_address_on_creation = true
depends_on = [aws_vpc_ipv6_cidr_block_association.main]
}Don't do this:
# WRONG: Empty IPv6 CIDR will cause error
resource "aws_subnet" "bad" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
ipv6_cidr_block = "" # Error!
}
# Either set a valid block or omit the argument entirelyAfter fixing your Terraform code, validate and apply:
# Validate syntax
terraform validate
# Plan to see what will be created
terraform plan
# Apply the changes
terraform applyThen verify in AWS:
# List all subnets in your VPC
aws ec2 describe-subnets --filters "Name=vpc-id,Values=vpc-xxxxx" \
--query 'Subnets[*].[SubnetId,CidrBlock,AvailabilityZone]' \
--output table
# Or check a specific subnet
aws ec2 describe-subnets --subnet-ids subnet-xxxxx \
--query 'Subnets[0]'If Terraform still shows errors, check that you haven't:
- Modified the VPC CIDR block (requires subnet updates)
- Created subnets outside Terraform (leads to state mismatch)
- Used conflicting resource names (check terraform state list)
### CIDR Block Mathematics
Understanding CIDR notation is critical for avoiding InvalidSubnet.Range errors:
Format: X.X.X.X/prefix
- X.X.X.X = Network address
- /prefix = Number of bits used for the network (0-32)
- Remaining bits = Host addresses
Examples:
- 10.0.0.0/16 = 10.0.0.0 to 10.0.255.255 (65,536 addresses)
- 10.0.0.0/24 = 10.0.0.0 to 10.0.0.255 (256 addresses)
- 10.0.0.0/28 = 10.0.0.0 to 10.0.0.15 (16 addresses - AWS minimum)
AWS Subnet Rules:
- Must be within VPC CIDR block
- Minimum size: /28 (16 addresses)
- Maximum size: /16 (65,536 addresses, same as largest VPC)
- First 4 addresses reserved (network, gateway, DNS, broadcast)
- Last address reserved (broadcast)
- Actual usable IPs per /24 subnet: 256 - 5 = 251
### Secondary CIDR Blocks
Terraform limitations with secondary CIDR blocks:
1. Association delay: AWS takes time to associate secondary CIDR blocks
2. State consistency: Terraform may think CIDR is ready before AWS does
3. Solution: Always add depends_on or run apply twice
### Terraform cidrsubnet() Function Details
cidrsubnet(prefix, newbits, netnum)- prefix: VPC CIDR (e.g., "10.0.0.0/16")
- newbits: Additional bits for subnet mask (e.g., 2)
- Original: /16
- Add 2 bits: /18
- netnum: Which subnet (0, 1, 2, ..., 2^newbits - 1)
Example:
VPC: 10.0.0.0/16
cidrsubnet("10.0.0.0/16", 2, 0) # = 10.0.0.0/18
cidrsubnet("10.0.0.0/16", 2, 1) # = 10.0.64.0/18
cidrsubnet("10.0.0.0/16", 2, 2) # = 10.0.128.0/18
cidrsubnet("10.0.0.0/16", 2, 3) # = 10.0.192.0/18### Local and Private IP Ranges
Use these ranges for private subnets (won't route to internet):
- Class A: 10.0.0.0/8 (10.0.0.0 to 10.255.255.255)
- Class B: 172.16.0.0/12 (172.16.0.0 to 172.31.255.255)
- Class C: 192.168.0.0/16 (192.168.0.0 to 192.168.255.255)
Link-local (auto-assigned): 169.254.0.0/16
### Debugging with Terraform
# View computed CIDR blocks
terraform console
> cidrsubnet("10.0.0.0/16", 2, 0)
"10.0.0.0/18"
# Destroy and recreate if stuck
terraform destroy -target aws_subnet.example
terraform apply
# Check state directly
terraform state show aws_subnet.example### AWS API Validation
InvalidSubnet.Range comes from AWS API validation, not Terraform. When Terraform sends:
{
"SubnetCidrBlock": "10.0.1.0/24",
"VpcId": "vpc-12345"
}AWS checks:
1. Is 10.0.1.0/24 a valid CIDR?
2. Is it within the VPC's CIDR blocks?
3. Does it overlap with existing subnets?
4. Is the size between /28 and /16?
If any check fails, you get InvalidSubnet.Range.
Error: Error installing helm release: cannot re-use a name that is still in use
How to fix "release name in use" error in Terraform with Helm
Error: Error creating GKE Cluster: BadRequest
BadRequest error creating GKE cluster in Terraform
Error: External program failed to produce valid JSON
External program failed to produce valid JSON
Error: Unsupported argument in child module call
How to fix "Unsupported argument in child module call" in Terraform
Error: network is unreachable
How to fix "network is unreachable" in Terraform