Quick Answer
# Valid CIDR: host bits after prefix must be zero
vpc_cidr = "10.0.0.0/16" # ✅
vpc_cidr = "10.0.1.0/16" # ❌ Host bit set (should be 10.0.0.0/16)
# Use cidrsubnet() for automatic subnet calculation
cidr_block = cidrsubnet("10.0.0.0/16", 8, 1) # → "10.0.1.0/24"
The Error
Error: "cidr_block" contains an invalid CIDR address: "10.0.1.0/16".
Did you mean "10.0.0.0/16"?
Error: InvalidParameterValue: Value (10.0.0.0/33) for parameter cidrBlock is invalid.
CIDR block should be between /16 and /28.
Error: InvalidVpc.Range: The CIDR '192.168.0.0/8' is invalid.
What Causes This
- Host bits not zeroed —
10.0.1.0/16should be10.0.0.0/16 - Invalid prefix length — AWS VPCs require
/16to/28 - Overlapping CIDRs — subnet overlaps with existing VPC or peered network
- Wrong format — missing prefix length or using IP range instead of CIDR
- Subnet doesn’t fit in VPC — subnet CIDR is outside the VPC CIDR range
CIDR Basics
10.0.0.0/16 → 10.0.0.0 to 10.0.255.255 (65,536 IPs)
10.0.1.0/24 → 10.0.1.0 to 10.0.1.255 (256 IPs)
10.0.1.0/28 → 10.0.1.0 to 10.0.1.15 (16 IPs)
The number after / is the network prefix length. Host bits must be zero:
| CIDR | Valid? | Fix |
|---|---|---|
10.0.0.0/16 | ✅ | — |
10.0.1.0/16 | ❌ | 10.0.0.0/16 |
10.0.1.0/24 | ✅ | — |
10.0.1.5/24 | ❌ | 10.0.1.0/24 |
10.0.0.0/33 | ❌ | Max is /32 |
Solution 1: Use cidrsubnet()
Let Terraform calculate valid subnets automatically:
variable "vpc_cidr" {
default = "10.0.0.0/16"
}
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
}
# Public subnets: 10.0.0.0/24, 10.0.1.0/24, 10.0.2.0/24
resource "aws_subnet" "public" {
count = 3
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index)
}
# Private subnets: 10.0.100.0/24, 10.0.101.0/24, 10.0.102.0/24
resource "aws_subnet" "private" {
count = 3
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index + 100)
}
cidrsubnet() Explained
cidrsubnet(prefix, newbits, netnum)
cidrsubnet("10.0.0.0/16", 8, 0) → "10.0.0.0/24" (16+8=24)
cidrsubnet("10.0.0.0/16", 8, 1) → "10.0.1.0/24"
cidrsubnet("10.0.0.0/16", 8, 255) → "10.0.255.0/24"
cidrsubnet("10.0.0.0/16", 4, 0) → "10.0.0.0/20" (16+4=20, 4096 IPs)
Solution 2: Validate CIDR in Variables
variable "vpc_cidr" {
type = string
validation {
condition = can(cidrhost(var.vpc_cidr, 0))
error_message = "Must be a valid CIDR block."
}
}
variable "subnet_cidr" {
type = string
validation {
condition = can(cidrhost(var.subnet_cidr, 0)) && tonumber(split("/", var.subnet_cidr)[1]) >= 16 && tonumber(split("/", var.subnet_cidr)[1]) <= 28
error_message = "Must be a valid CIDR with prefix /16 to /28."
}
}
Solution 3: Avoid Overlapping CIDRs
# ❌ These overlap — subnets both start at 10.0.0.0
resource "aws_subnet" "a" { cidr_block = "10.0.0.0/24" }
resource "aws_subnet" "b" { cidr_block = "10.0.0.0/25" } # Overlaps with a!
# ✅ Non-overlapping
resource "aws_subnet" "a" { cidr_block = "10.0.0.0/24" }
resource "aws_subnet" "b" { cidr_block = "10.0.1.0/24" }
Check for overlaps with VPC peering:
# List all VPC CIDRs
aws ec2 describe-vpcs --query 'Vpcs[].{ID:VpcId,CIDR:CidrBlock}' --output table
# List peering CIDRs
aws ec2 describe-vpc-peering-connections \
--query 'VpcPeeringConnections[].{Req:RequesterVpcInfo.CidrBlock,Acc:AccepterVpcInfo.CidrBlock}'
AWS VPC CIDR Constraints
| Constraint | Value |
|---|---|
| Smallest VPC | /28 (16 IPs) |
| Largest VPC | /16 (65,536 IPs) |
| Allowed ranges | 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 (RFC 1918) |
| AWS reserved per subnet | 5 IPs (first 4 + last 1) |
| Secondary CIDRs | Up to 4 additional CIDRs per VPC |
Hands-On Courses
- Terraform for Beginners on CopyPasteLearn
- Terraform By Example — practical code examples
Conclusion
Invalid CIDR errors mean host bits aren’t zeroed, the prefix is out of range, or subnets overlap. Use cidrsubnet() to calculate valid subnets automatically — it eliminates manual CIDR math errors. Validate CIDR variables at the variable level and check for overlaps with existing VPCs before deploying.
