TerraformPilot

Troubleshooting

Fix Terraform Route53 Record - InvalidChangeBatch

Fix Route53 InvalidChangeBatch errors in Terraform. Handle duplicate records, alias target issues, hosted zone ID mismatches, and CNAME conflicts.

LLuca Berton2 min read

Quick Answer

#

The DNS record change violates Route53 rules — usually a duplicate record, CNAME conflict, alias target mismatch, or wrong hosted zone. Check the specific error detail after InvalidChangeBatch:.

The Error

#
Error: creating Route53 Record: InvalidChangeBatch:
  Tried to create resource record set [name='example.com.', type='A']
  but it already exists.
Error: creating Route53 Record: InvalidChangeBatch:
  RRSet of type CNAME with DNS name example.com. is not permitted
  at apex of zone example.com.
Error: creating Route53 Record: InvalidChangeBatch:
  Tried to create an alias that targets another alias, but the
  target alias is not valid.

What Causes This Error

#

1. Record Already Exists

#

A record with the same name and type was created manually or by another tool.

2. CNAME at Zone Apex

#

You can't create a CNAME record at the root of a hosted zone (example.com). Use an alias record instead.

3. CNAME Conflict

#

A CNAME record can't coexist with any other record type at the same name.

4. Wrong Hosted Zone ID

#

The hosted zone ID doesn't match the domain, or you're using a private zone when you need public.

How to Fix It

#

Solution 1: Import Existing Records

#
# Check existing records
aws route53 list-resource-record-sets --hosted-zone-id Z1234 \
  --query "ResourceRecordSets[?Name=='example.com.']"
 
# Import — format: zone_id_recordname_type_set-identifier
terraform import aws_route53_record.www Z1234_www.example.com_A

Solution 2: Use Alias for Zone Apex

#
# BAD — CNAME at zone apex
resource "aws_route53_record" "root" {
  zone_id = var.zone_id
  name    = "example.com"
  type    = "CNAME"            # NOT allowed at apex
  records = ["my-alb.us-east-1.elb.amazonaws.com"]
  ttl     = 300
}
 
# GOOD — Alias record at zone apex
resource "aws_route53_record" "root" {
  zone_id = var.zone_id
  name    = "example.com"
  type    = "A"
 
  alias {
    name                   = aws_lb.main.dns_name
    zone_id                = aws_lb.main.zone_id
    evaluate_target_health = true
  }
}

Solution 3: Fix CNAME Conflicts

#
# BAD — CNAME + A record at same name
resource "aws_route53_record" "www_cname" {
  name    = "www.example.com"
  type    = "CNAME"
  records = ["example.com"]
}
resource "aws_route53_record" "www_a" {
  name    = "www.example.com"
  type    = "A"                # CONFLICT — can't have A alongside CNAME
  records = ["1.2.3.4"]
}
 
# GOOD — pick one type
resource "aws_route53_record" "www" {
  zone_id = var.zone_id
  name    = "www.example.com"
  type    = "A"
 
  alias {
    name                   = aws_lb.main.dns_name
    zone_id                = aws_lb.main.zone_id
    evaluate_target_health = true
  }
}

Solution 4: Verify Hosted Zone

#
# List hosted zones
aws route53 list-hosted-zones --query 'HostedZones[].{Id:Id,Name:Name,Private:Config.PrivateZone}'
 
# Make sure you're using the public zone for public records
data "aws_route53_zone" "main" {
  name         = "example.com"
  private_zone = false  # Explicitly request public zone
}

Route53 Record Rules

#
RuleDetails
No CNAME at apexUse alias A/AAAA record instead
CNAME is exclusiveNo other record types at the same name
Alias targets must be validALB, CloudFront, S3, API Gateway, another Route53 record
Record names end with .Route53 adds trailing dot automatically

Troubleshooting Checklist

#
  1. ✅ Does the record already exist? (aws route53 list-resource-record-sets)
  2. ✅ Is it a CNAME at zone apex? Switch to alias A record
  3. ✅ Is there a CNAME conflict at the same name?
  4. ✅ Is the hosted zone ID correct? (Public vs private?)
  5. ✅ Is the alias target valid and in the correct region?

Prevention Tips

#
  • Use alias records instead of CNAME for AWS resources (free, no TTL, health checks)
  • Use data "aws_route53_zone" to look up zone IDs dynamically
  • Import existing records before creating duplicates
  • Use allow_overwrite = true cautiously if you want Terraform to overwrite existing records
#

Conclusion

#

InvalidChangeBatch means the DNS change violates Route53 rules. Use alias records at zone apex instead of CNAME, avoid CNAME conflicts, verify the hosted zone ID, and import existing records rather than creating duplicates.

#Terraform#AWS#Troubleshooting#Error Fix

Share this article