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
- 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
- Check the wrapped error for credential validation failures and correct the provider options (token, profile, etc.)
- Fix the provider name to match the module's documented name exactly
- 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
- Pin and rebuild custom binaries with xcaddy in CI; record the --with set next to the config
- Run caddy list-modules as a post-build assertion
- Keep provider tokens in env placeholders and validate them in the same pipeline
- When upgrading plugins, re-read their option schema - names change between majors
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
- failed to load network_proxy module: %v
- filling in global issuer defaults for AP %d, issuer %d: %v
- acme_dns specified without DNS provider config, but no provi
- filling in global issuer defaults for issuer %d: %v
- expanding DNS override domain '%s': %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/61324bbee01b6687.
Report an issue: GitHub.