kubernetes/kops · error
error creating DNS HostedZone %q: %v
Error message
error creating DNS HostedZone %q: %v
What it means
RenderAWS failed to create the Route53 hosted zone: the CreateHostedZone API call returned an error when provisioning a new DNSZone task (no existing zone matched). All Route53 creation failures — permissions, limits, invalid names, conflicting CallerReference — surface through this wrapper.
Source
Thrown at upup/pkg/fi/cloudup/awstasks/dnszone.go:196
name := aws.ToString(e.DNSName)
if a == nil {
request := &route53.CreateHostedZoneInput{}
request.Name = e.DNSName
nonce := rand.Int63()
request.CallerReference = aws.String(strconv.FormatInt(nonce, 10))
if e.PrivateVPC != nil {
request.VPC = &route53types.VPC{
VPCId: e.PrivateVPC.ID,
VPCRegion: route53types.VPCRegion(t.Cloud.Region()),
}
}
klog.V(2).Infof("Creating Route53 HostedZone with Name %q", name)
response, err := t.Cloud.Route53().CreateHostedZone(ctx, request)
if err != nil {
return fmt.Errorf("error creating DNS HostedZone %q: %v", name, err)
}
e.ZoneID = response.HostedZone.Id
} else {
if changes.PrivateVPC != nil {
request := &route53.AssociateVPCWithHostedZoneInput{
HostedZoneId: a.ZoneID,
VPC: &route53types.VPC{
VPCId: e.PrivateVPC.ID,
VPCRegion: route53types.VPCRegion(t.Cloud.Region()),
},
}
changes.PrivateVPC = nil
klog.V(2).Infof("Updating DNSZone %q", name)
_, err := t.Cloud.Route53().AssociateVPCWithHostedZone(ctx, request)View on GitHub (pinned to 4c8573c808)
Solutions
- Read the wrapped %v cause; if HostedZoneAlreadyExists, set the existing zone's ID in the spec instead of creating a new one
- If AccessDenied, grant the kOps IAM role route53:CreateHostedZone (and AssociateVPCWithHostedZone for private zones)
- If InvalidDomainName, correct cluster.spec.dns/name to a valid lowercase domain
- If TooManyHostedZones, delete unused zones or request a limit increase
- If InvalidVPCAssociation, verify the PrivateVPC ID exists in t.Cloud.Region()
Example fix
// before request.Name = e.DNSName // e.g. "Cluster.Example.COM" → InvalidDomainName // after request.Name = aws.String(strings.ToLower(strings.TrimSuffix(aws.ToString(e.DNSName), ".")))
Defensive patterns
Strategy: try-catch
Validate before calling
name := strings.ToLower(strings.TrimSuffix(aws.ToString(e.DNSName), "."))
if name == "" || strings.ContainsAny(name, " _") || net.ParseIP(name) != nil {
return fmt.Errorf("invalid hosted zone name %q", name)
}
if e.PrivateVPC != nil {
if _, err := ec2.DescribeVpcs(ctx, &ec2.DescribeVpcsInput{VpcIds: []string{aws.ToString(e.PrivateVPC.ID)}}); err != nil {
return fmt.Errorf("VPC %s not found/accessible in region: %w", aws.ToString(e.PrivateVPC.ID), err)
}
}
// confirm no zone already exists with this name
out, _ := r53.ListHostedZonesByName(ctx, &route53.ListHostedZonesByNameInput{DNSName: aws.String(name + ".")})
for _, z := range out.HostedZones {
if aws.ToString(z.Name) == name+"." {
return fmt.Errorf("zone %s already exists (%s); reference its ID instead of creating", name, aws.ToString(z.Id))
}
} Type guard
func isRetryableRoute53Error(err error) bool {
switch awsup.AWSErrorCode(err) {
case "Throttling", "RequestLimitExceeded", "ServiceUnavailable", "InternalError":
return true
}
return false
} Try / catch
response, err := t.Cloud.Route53().CreateHostedZone(ctx, request)
if err != nil {
switch awsup.AWSErrorCode(err) {
case "HostedZoneAlreadyExists":
// adopt existing zone instead of failing
return adoptExistingZone(ctx, t, e, err)
case "TooManyHostedZones":
return fmt.Errorf("hosted zone limit reached for account: %w", err)
case "InvalidDomainName":
return fmt.Errorf("invalid DNS name %q: %w", name, err)
}
if isRetryableRoute53Error(err) {
return retryCreateWithBackoff(ctx, request)
}
return fmt.Errorf("error creating DNS HostedZone %q: %w", name, err)
} Prevention
- Grant route53:CreateHostedZone (plus route53:AssociateVPCWithHostedZone for private zones) to the kOps role
- Validate cluster DNS name is a lowercase valid domain before creating the cluster
- Check the account's hosted zone limit (`aws service-quotas ...`) for large multi-cluster setups
- Search for an existing zone with the same name and reference its ID rather than creating a duplicate
- For private zones, verify the VPC ID exists in the same region as the cluster
When it happens
Trigger: CreateHostedZone errors: AccessDenied (no route53:CreateHostedZone), InvalidDomainName (bad DNSName), TooManyHostedZones (account limit, historically 500 public zones), HostedZoneAlreadyExists for a re-used CallerReference, InvalidVPCAssociation inputs for private zones (bad VPC id/region).
Common situations: Public zone for a domain already delegated elsewhere hitting account zone limits; misconfigured cluster DNS name (typo, uppercase, trailing dot issues); IAM role too restricted; creating a private zone with a VPC ID from the wrong region; rate limiting during parallel cluster creation.
Related errors
- error fetching DNS HostedZone %q: %v
- error listing DNS HostedZones: %v
- error fetching DNS HostedZone by id %q: %v
- error applying DNS changeset for zone %s: %v
- error listing resource record sets: %w
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/aa58c86fffec9825.
Report an issue: GitHub.