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

  1. Check the wrapped error and provider logs; re-issue/refresh the API token with read+write scope on the zone.
  2. Confirm the token's zone permissions cover the domain in the message.
  3. Back off / reduce simultaneous ECH publications if rate-limited.
  4. 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

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


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/89ff22cf99ca943e. Report an issue: GitHub.