{"record":{"id":"399f958acc1109dd","repo":"kubernetes/kops","slug":"error-listing-dns-zones-v","errorCode":null,"errorMessage":"error listing DNS zones: %v","messagePattern":"error listing DNS zones: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/dns.go","lineNumber":62,"sourceCode":"}\n\nfunc findZone(cluster *kops.Cluster, cloud fi.Cloud) (dnsprovider.Zone, error) {\n\tdns, err := cloud.DNS()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error building DNS provider: %v\", err)\n\t}\n\tif dns == nil {\n\t\treturn nil, nil\n\t}\n\n\tzonesProvider, ok := dns.Zones()\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"error getting DNS zones provider\")\n\t}\n\n\tzones, err := zonesProvider.List()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error listing DNS zones: %v\", err)\n\t}\n\n\tvar matches []dnsprovider.Zone\n\tfindName := strings.TrimSuffix(cluster.Spec.DNSZone, \".\")\n\tfor _, zone := range zones {\n\t\tid := zone.ID()\n\t\tname := strings.TrimSuffix(zone.Name(), \".\")\n\t\tif id == cluster.Spec.DNSZone || name == findName {\n\t\t\tmatches = append(matches, zone)\n\t\t}\n\t}\n\tif len(matches) == 0 {\n\t\treturn nil, fmt.Errorf(\"cannot find DNS Zone %q.  Please pre-create the zone and set up NS records so that it resolves\", cluster.Spec.DNSZone)\n\t}\n\n\tif len(matches) > 1 {\n\t\tklog.Infof(\"Found multiple DNS Zones matching %q, please set the cluster's spec.dnsZone to the desired Zone ID:\", cluster.Spec.DNSZone)\n\t\tfor _, zone := range zones {","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/dns.go#L44-L80","documentation":"findZone enumerates DNS zones via zonesProvider.List(). Any failure listing zones (auth errors, throttling, network problems, API errors) is wrapped as 'error listing DNS zones: %v'. This prevents resolving the cluster's DNSZone to a concrete provider zone.","triggerScenarios":"validateDNS/precreateDNS → findZone when the provider's List() call errors: expired/insufficient credentials, rate limiting, network outage, or DNS API returning an error for the account.","commonSituations":"AWS credentials without route53:ListHostedZones permission; Azure/GCP DNS API quota or auth failures; transient network failures during `kops create cluster` or `kops validate cluster`.","solutions":["Read the wrapped cause and fix the underlying API/auth/network issue (e.g. add route53:ListHostedZones IAM permission)","Retry the command if the failure was transient (throttling/network)","Verify credentials for the DNS provider account (AWS_PROFILE, AZURE creds, GCP application-default)"],"exampleFix":"// before: IAM missing list permission\n{\"Effect\": \"Deny\", \"Action\": \"route53:ListHostedZones\"}\n// after: allow read on route53 zones\n{\"Effect\": \"Allow\", \"Action\": [\"route53:ListHostedZones\", \"route53:GetHostedZone\"], \"Resource\": \"*\"}","handlingStrategy":"retry","validationCode":"// Pre-flight: attempt a lightweight zone list with same credentials\nzones, err := zonesProvider.List()\nif err != nil { return fmt.Errorf(\"preflight DNS list failed: %w\", err) }","typeGuard":null,"tryCatchPattern":"zones, err := zonesProvider.List()\nif err != nil {\n    if isTransient(err) {\n        time.Sleep(backoff)\n        zones, err = zonesProvider.List()\n    }\n    if err != nil { return err }\n}","preventionTips":["Grant least-privilege IAM read permissions for DNS zone listing","Handle rate limits with exponential backoff","Verify provider credentials before running kops commands"],"tags":["dns","api-error","permissions","zone-lookup"],"backgroundTag":"dns-zone-list-failed","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}