{"record":{"id":"89ff22cf99ca943e","repo":"caddyserver/caddy","slug":"unable-to-get-existing-dns-records-to-publish-ech","errorCode":null,"errorMessage":"unable to get existing DNS records to publish ECH data to HTTPS DNS record: %w","messagePattern":"unable to get existing DNS records to publish ECH data to HTTPS DNS record: %w","errorType":"exception","errorClass":"PublishECHConfigListErrors","httpStatus":null,"severity":"warning","filePath":"modules/caddytls/ech.go","lineNumber":842,"sourceCode":"\terrs := make(PublishECHConfigListErrors)\n\nnextName:\n\tfor _, domain := range innerNames {\n\t\tzone, err := certmagic.FindZoneByFQDN(ctx, dnsPub.logger, domain, nameservers)\n\t\tif err != nil {\n\t\t\terrs[domain] = fmt.Errorf(\"could not determine zone for domain: %w (domain=%s nameservers=%v)\", err, domain, nameservers)\n\t\t\tcontinue\n\t\t}\n\n\t\trelName := libdns.RelativeName(domain+\".\", zone)\n\n\t\t// get existing records for this domain; we need to make sure another\n\t\t// record exists for it so we don't accidentally trample a wildcard; we\n\t\t// also want to get any HTTPS record that may already exist for it so\n\t\t// we can augment the ech SvcParamKey with any other existing SvcParams\n\t\trecs, err := dnsPub.provider.GetRecords(ctx, zone)\n\t\tif err != nil {\n\t\t\terrs[domain] = fmt.Errorf(\"unable to get existing DNS records to publish ECH data to HTTPS DNS record: %w\", err)\n\t\t\tcontinue\n\t\t}\n\t\tvar httpsRec libdns.ServiceBinding\n\t\tvar nameHasExistingRecord bool\n\t\tfor _, rec := range recs {\n\t\t\trr := rec.RR()\n\t\t\tif rr.Name == relName {\n\t\t\t\t// CNAME records are exclusive of all other records, so we cannot publish an HTTPS\n\t\t\t\t// record for a domain that is CNAME'd. See #6922.\n\t\t\t\tif rr.Type == \"CNAME\" {\n\t\t\t\t\tdnsPub.logger.Warn(\"domain has CNAME record, so unable to publish ECH data to HTTPS record\",\n\t\t\t\t\t\tzap.String(\"domain\", domain),\n\t\t\t\t\t\tzap.String(\"cname_value\", rr.Data))\n\t\t\t\t\tcontinue nextName\n\t\t\t\t}\n\t\t\t\tnameHasExistingRecord = true\n\t\t\t\tif svcb, ok := rec.(libdns.ServiceBinding); ok && svcb.Scheme == \"https\" {\n\t\t\t\t\tif svcb.Target == \"\" || svcb.Target == \".\" {","sourceCodeStart":824,"sourceCodeEnd":860,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/ech.go#L824-L860","documentation":"Before writing the HTTPS RR with ECH SvcParams, Caddy lists all records in the target zone via the configured DNS provider (GetRecords) — both to avoid trampling a wildcard and to merge with any existing HTTPS record's SvcParams. This error wraps a provider API failure during that listing, recorded per-domain in PublishECHConfigListErrors and skipping to the next name.","triggerScenarios":"provider.GetRecords(ctx, zone) failing: invalid/expired API token, insufficient permissions for the zone, provider rate limit, network error to the provider API.","commonSituations":"Expired DNS provider token; token scoped to a different zone than the domain's; hitting provider API rate limits when many names publish at once; provider outage.","solutions":["Check the wrapped error and provider logs; re-issue/refresh the API token with read+write scope on the zone.","Confirm the token's zone permissions cover the domain in the message.","Back off / reduce simultaneous ECH publications if rate-limited.","Retry after the provider-side incident resolves."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Pre-flight provider access with a cheap listing.\nif _, err := provider.GetRecords(ctx, zone); err != nil {\n    return fmt.Errorf(\"provider cannot list zone %s: %w\", zone, err)\n}","typeGuard":null,"tryCatchPattern":"var perrs caddytls.PublishECHConfigListErrors\nif errors.As(err, &perrs) {\n    for d, e := range perrs {\n        if strings.Contains(e.Error(), \"unable to get existing DNS records\") {\n            log.Printf(\"%s: check provider token/permissions: %v\", d, e)\n        }\n    }\n}","preventionTips":["Give DNS tokens read+write scope on all zones you publish to.","Rotate tokens before expiry; store them via secrets management, not plaintext configs.","Watch provider rate limits when many names publish simultaneously."],"tags":["tls","ech","dns","api","authentication"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}