coredns/coredns · error

invalid ACME domain %q: %w

Error message

invalid ACME domain %q: %w

What it means

Validation error in the ACME helper normalizeACMEDomain. The domain is unusable for certificate issuance — it is empty, consists only of the wildcard prefix, contains an interior '*', or is an IP address (ACME cannot issue for IPs) — so the wrapped reason is reported to the caller.

Source

Thrown at plugin/tls/acme.go:87

		root = "."
	}
	storage, err := filepath.Abs(filepath.Join(root, ".coredns", "acme"))
	if err != nil {
		return acmeOptions{}, fmt.Errorf("resolving ACME storage directory: %w", err)
	}
	return acmeOptions{ca: certmagic.DefaultACME.CA, storage: storage}, nil
}

func normalizeACMEDomain(domain string) (string, error) {
	domain = strings.ToLower(strings.TrimSuffix(domain, "."))
	wildcard := strings.HasPrefix(domain, "*.")
	check := strings.TrimPrefix(domain, "*.")
	if domain == "" || check == "" || strings.Contains(check, "*") || net.ParseIP(check) != nil {
		return "", fmt.Errorf("invalid ACME domain %q", domain)
	}
	check, err := idna.Lookup.ToASCII(check)
	if err != nil {
		return "", fmt.Errorf("invalid ACME domain %q: %w", domain, err)
	}
	if _, ok := dns.IsDomainName(check); !ok {
		return "", fmt.Errorf("invalid ACME domain %q", domain)
	}
	if wildcard {
		return "*." + check, nil
	}
	return check, nil
}

func validateACMEOptions(o *acmeOptions) error {
	if len(o.domains) == 0 {
		return errors.New("ACME requires at least one domain")
	}

	seen := make(map[string]struct{}, len(o.domains))
	domains := o.domains[:0]
	for _, domain := range o.domains {

View on GitHub (pinned to 558c9757a9)

Solutions

  1. Correct the internationalized domain name spelling in the Corefile
  2. Use valid punycode (xn--...) ASCII form directly
  3. Save the Corefile as UTF-8 and re-check for corrupted bytes
  4. Test the name with an IDNA library before deploying

Example fix

// before (invalid punycode)
tls acme xn--example-.org
// after (valid IDNA)
tls acme Bücherei.example.org  // or xn--bcherei-k9a.example.org
Defensive patterns

Strategy: validation

Validate before calling

if _, err := idna.Lookup.ToASCII(domain); err != nil {
	// invalid IDNA name — fix before putting in Corefile
	return err
}

Try / catch

normalized, err := normalizeACMEDomain(d)
if err != nil {
	if strings.Contains(err.Error(), "idna") || errors.Unwrap(err) != nil {
		log.Printf("IDNA conversion failed for %q: %v", d, err)
	}
}

Prevention

When it happens

Trigger: normalizeACMEDomain receives a domain whose IDNA conversion fails, e.g. malformed Unicode labels, invalid punycode, or disallowed characters per IDNA2008 rules.

Common situations: Copy-pasted internationalized domain containing disallowed characters or a bad "xn--" punycode label; encoding corruption in the Corefile (wrong charset).

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of coredns/coredns@558c9757a9 (2026-09-06). Data as JSON: /api/errors/0e343dbafa67b155. Report an issue: GitHub.