caddyserver/caddy · error

loading DNS provider module: %v

Error message

loading DNS provider module: %v

What it means

Returned by ACMEIssuer.Provision (modules/caddytls/acmeissuer.go:204) when ctx.LoadModule fails to instantiate the configured DNS challenge provider module (the dns directive's provider, e.g. cloudflare). Wrapped causes: the provider module name is not registered (plugin not compiled into the binary), the module's own provisioning failed (bad credentials), or the JSON caddy module field is malformed.

Source

Thrown at modules/caddytls/acmeissuer.go:204

	}

	// expand DNS override domain, if non-empty
	if iss.Challenges != nil && iss.Challenges.DNS != nil && iss.Challenges.DNS.OverrideDomain != "" {
		overrideDomain, err := repl.ReplaceOrErr(iss.Challenges.DNS.OverrideDomain, true, true)
		if err != nil {
			return fmt.Errorf("expanding DNS override domain '%s': %v", iss.Challenges.DNS.OverrideDomain, err)
		}
		iss.Challenges.DNS.OverrideDomain = overrideDomain
	}

	// DNS challenge provider, if not already established
	if iss.Challenges != nil && iss.Challenges.DNS != nil && iss.Challenges.DNS.solver == nil {
		var prov certmagic.DNSProvider
		if iss.Challenges.DNS.ProviderRaw != nil {
			// a challenge provider has been locally configured - use it
			val, err := ctx.LoadModule(iss.Challenges.DNS, "ProviderRaw")
			if err != nil {
				return fmt.Errorf("loading DNS provider module: %v", err)
			}
			prov = val.(certmagic.DNSProvider)
		} else if tlsAppIface, err := ctx.AppIfConfigured("tls"); err == nil {
			// no locally configured DNS challenge provider, but if there is
			// a global DNS module configured with the TLS app, use that
			tlsApp := tlsAppIface.(*TLS)
			if tlsApp.dns != nil {
				prov = tlsApp.dns.(certmagic.DNSProvider)
			}
		}
		if prov == nil {
			return fmt.Errorf("DNS challenge enabled, but no DNS provider configured")
		}
		iss.Challenges.DNS.solver = &certmagic.DNS01Solver{
			DNSManager: certmagic.DNSManager{
				DNSProvider:        prov,
				TTL:                time.Duration(iss.Challenges.DNS.TTL),
				PropagationDelay:   time.Duration(iss.Challenges.DNS.PropagationDelay),

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Run caddy list-modules and confirm the DNS provider (e.g. dns.providers.cloudflare) is present; if missing, build with xcaddy: xcaddy build --with github.com/caddy-dns/cloudflare
  2. Check the wrapped error for credential validation failures and correct the provider options (token, profile, etc.)
  3. Fix the provider name to match the module's documented name exactly
  4. Keep credentials in env placeholders ({env.CF_API_TOKEN}) and ensure they are set in the service environment

Example fix

# before: stock binary, no plugin
 example.com {
   tls {
     dns cloudflare {env.CF_API_TOKEN}
   }
 }

# after: build with the plugin, keep the config
xcaddy build --with github.com/caddy-dns/cloudflare
# then deploy the new binary; config unchanged
Defensive patterns

Strategy: validation

Validate before calling

# confirm the provider module exists in the binary before deploying config
caddy list-modules | grep -q 'dns.providers.cloudflare' || {
  echo "cloudflare DNS plugin missing; rebuild with xcaddy"; exit 1; }
# and confirm credentials resolve
test -n "$CF_API_TOKEN" || { echo "CF_API_TOKEN unset"; exit 1; }

Try / catch

if err := issuer.Provision(ctx); err != nil {
    if strings.Contains(err.Error(), "loading DNS provider module") {
        // unwrap for the real cause: missing plugin (rebuild) or bad creds (fix options)
    }
    return err
}

Prevention

When it happens

Trigger: Using tls { dns <provider> ... } with a provider name that does not exist in this Caddy build (e.g. a DNS plugin from xcaddy that was not included), or the provider's Provision failing - typically invalid/missing API credentials for cloudflare/route53/etc.

Common situations: Swapping the stock caddy binary (no plugins) for a config written for a plugin build; plugin name typos (cloudflare vs cloud_flare); provider credentials given as a literal that fails validation; version drift where a plugin changed its option names after an upgrade.

Related errors


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