caddyserver/caddy · warning · PublishECHConfigListErrors
unable to get existing DNS records to publish ECH data to HT
Error message
unable to get existing DNS records to publish ECH data to HTTPS DNS record: %w
What it means
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.
Source
Thrown at modules/caddytls/ech.go:842
errs := make(PublishECHConfigListErrors)
nextName:
for _, domain := range innerNames {
zone, err := certmagic.FindZoneByFQDN(ctx, dnsPub.logger, domain, nameservers)
if err != nil {
errs[domain] = fmt.Errorf("could not determine zone for domain: %w (domain=%s nameservers=%v)", err, domain, nameservers)
continue
}
relName := libdns.RelativeName(domain+".", zone)
// get existing records for this domain; we need to make sure another
// record exists for it so we don't accidentally trample a wildcard; we
// also want to get any HTTPS record that may already exist for it so
// we can augment the ech SvcParamKey with any other existing SvcParams
recs, err := dnsPub.provider.GetRecords(ctx, zone)
if err != nil {
errs[domain] = fmt.Errorf("unable to get existing DNS records to publish ECH data to HTTPS DNS record: %w", err)
continue
}
var httpsRec libdns.ServiceBinding
var nameHasExistingRecord bool
for _, rec := range recs {
rr := rec.RR()
if rr.Name == relName {
// CNAME records are exclusive of all other records, so we cannot publish an HTTPS
// record for a domain that is CNAME'd. See #6922.
if rr.Type == "CNAME" {
dnsPub.logger.Warn("domain has CNAME record, so unable to publish ECH data to HTTPS record",
zap.String("domain", domain),
zap.String("cname_value", rr.Data))
continue nextName
}
nameHasExistingRecord = true
if svcb, ok := rec.(libdns.ServiceBinding); ok && svcb.Scheme == "https" {
if svcb.Target == "" || svcb.Target == "." {View on GitHub (pinned to 50e54ee279)
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.
Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight provider access with a cheap listing.
if _, err := provider.GetRecords(ctx, zone); err != nil {
return fmt.Errorf("provider cannot list zone %s: %w", zone, err)
} Try / catch
var perrs caddytls.PublishECHConfigListErrors
if errors.As(err, &perrs) {
for d, e := range perrs {
if strings.Contains(e.Error(), "unable to get existing DNS records") {
log.Printf("%s: check provider token/permissions: %v", d, e)
}
}
} Prevention
- 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.
When it happens
Trigger: provider.GetRecords(ctx, zone) failing: invalid/expired API token, insufficient permissions for the zone, provider rate limit, network error to the provider API.
Common situations: 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.
Related errors
- unable to publish ECH data to HTTPS DNS record: %w (zone=%s
- loading ECH DNS provider module: %v
- ECH DNS provider module is not an ECH DNS Provider: %v
- could not determine zone for domain: %w (domain=%s nameserve
- public name length (%d) must be in the range 1-255
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/89ff22cf99ca943e.
Report an issue: GitHub.