AWS WAF has account-level quotas on the number of WebACLs, rules, and other resources you can create. This error occurs when you exceed those limits. Resolve it by consolidating resources, removing unused WAF entities, or requesting quota increases.
The WAFLimitsExceededException error occurs when you attempt to create or modify an AWS WAF WebACL (Web Access Control List) and the operation would exceed one of AWS's account-level resource quotas. AWS WAF enforces several limits per account per region, including: - Maximum number of WebACLs per account (default: 100, can be increased) - Maximum Web ACL Capacity Units (WCU) per WebACL (currently up to 5,000) - Maximum number of rule groups, IP sets, and regex pattern sets This error commonly appears in Terraform when deploying or updating aws_wafv2_web_acl resources. The error message from AWS doesn't always specify which quota was exceeded, making troubleshooting more difficult.
Navigate to AWS WAF & Shield in the AWS Management Console and check your current usage against limits:
1. Go to AWS WAF & Shield > Web ACLs > check how many exist in your region
2. Select your WebACL and review the "Capacity" tab to see current WCU usage vs 5,000 limit
3. Check Rule groups, IP sets, and Regex pattern sets quotas under "Resources"
4. Compare against your region's limits in the AWS WAF quotas documentation
This helps identify which specific resource limit is being exceeded.
Instead of creating single-use rule groups or IP sets, reuse them across multiple WebACLs:
# BAD: Creating a separate IP set for each WebACL
resource "aws_wafv2_ip_set" "api_ips_webacl1" {
name = "api-ips-webacl1"
# ...
}
resource "aws_wafv2_ip_set" "api_ips_webacl2" {
name = "api-ips-webacl2"
# ...
}
# GOOD: Create one shared IP set
resource "aws_wafv2_ip_set" "api_ips" {
name = "api-ips-shared"
# ...
}
# Reference the same IP set in multiple WebACLs
resource "aws_wafv2_web_acl" "api_protection_1" {
name = "api-protection-1"
rules {
statement {
ip_set_reference_statement {
arn = aws_wafv2_ip_set.api_ips.arn
}
}
}
}
resource "aws_wafv2_web_acl" "api_protection_2" {
name = "api-protection-2"
rules {
statement {
ip_set_reference_statement {
arn = aws_wafv2_ip_set.api_ips.arn
}
}
}
}This reduces your total resource count significantly.
Instead of many individual rules, use nested AND/OR statements within a single rule to reduce WCU consumption:
# BAD: Multiple rules consuming more WCU
resource "aws_wafv2_web_acl" "example" {
rules {
action {
block {}
}
statement {
rate_based_statement {
limit = 2000
}
}
}
rules {
action {
block {}
}
statement {
ip_set_reference_statement {
arn = aws_wafv2_ip_set.malicious_ips.arn
}
}
}
rules {
action {
block {}
}
statement {
sql_injection_match_statement {}
}
}
}
# GOOD: Combine with AND statement
resource "aws_wafv2_web_acl" "example" {
rules {
action {
block {}
}
statement {
and_statement {
statement {
rate_based_statement {
limit = 2000
}
}
statement {
or_statement {
statement {
ip_set_reference_statement {
arn = aws_wafv2_ip_set.malicious_ips.arn
}
}
statement {
sql_injection_match_statement {}
}
}
}
}
}
}
}Check your WebACL capacity usage in the console to understand WCU consumption before and after optimizations.
Identify and remove WebACLs, rule groups, IP sets, and regex pattern sets that are no longer in use:
# In Terraform, remove unused resources from your configuration,
# then run terraform plan to verify what will be deleted
terraform plan
# Once verified, apply the changes
terraform applyUse the AWS CLI to find unused resources:
# List all WebACLs in a region
aws wafv2 list-web-acls --scope REGIONAL --region us-east-1
# List all rule groups
aws wafv2 list-rule-groups --scope REGIONAL --region us-east-1
# List all IP sets
aws wafv2 list-ip-sets --scope REGIONAL --region us-east-1Check your CloudFront or ALB associations to ensure you're not deleting WebACLs that are still in use.
If you've optimized your resources and still need more capacity, request a quota increase:
1. Go to AWS Service Quotas console
2. Search for "WAF" or "Web ACL"
3. Find the quota you need to increase (e.g., "Web ACLs per account")
4. Click on the quota and select "Request quota increase"
5. Enter the desired count and submit
6. Wait for AWS to process the request (typically 1-2 hours, but can take longer)
Example quota names:
- Web ACLs per account (default: 100)
- Web ACL capacity units (WCU) per Web ACL (current: 5000)
- Rule groups per account (default: 100)
- IP sets per account (default: 100)
- Regex pattern sets per account (default: 10)
After approval, your Terraform apply should succeed.
AWS WAF quotas are per-region. If you're deploying to multiple regions and hitting limits, this is expected behavior:
# Each region has independent quotas
provider "aws" {
alias = "us-east-1"
region = "us-east-1"
}
provider "aws" {
alias = "eu-west-1"
region = "eu-west-1"
}
# These use separate quotas and don't count against each other
resource "aws_wafv2_web_acl" "us" {
provider = aws.us-east-1
name = "api-protection-us"
# ...
}
resource "aws_wafv2_web_acl" "eu" {
provider = aws.eu-west-1
name = "api-protection-eu"
# ...
}If you're seeing errors in multiple regions, check each region's quota separately. You may only need to increase quotas in specific regions.
Web ACL Capacity Units (WCU) Calculation: AWS WAF assigns WCU values to rules based on complexity. Simple rules (IP match, string match) cost fewer WCU than complex nested statements. If approaching the 5,000 WCU limit, review the "Capacity" tab in your WebACL to see which rules consume the most units.
Region-Specific Limits: Quotas are per-region and per-account. A WebACL in us-east-1 doesn't count toward your quota in eu-west-1. However, the total number of entities across all regions may hit your account-level limits for some resource types.
Managed Rules Consideration: AWS Managed Rules consume WCU when referenced. A single AWS Managed Rule Group (e.g., AWSManagedRulesCommonRuleSet) can consume 700+ WCU, so account for this when designing your WebACL.
Terraform State: When requesting quota increases, you may need to adjust your Terraform configuration after the quota is approved. Sometimes re-running terraform apply without changes is necessary to trigger the operation against the higher quota.
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