{"record":{"id":"61324bbee01b6687","repo":"caddyserver/caddy","slug":"loading-dns-provider-module-v","errorCode":null,"errorMessage":"loading DNS provider module: %v","messagePattern":"loading DNS provider module: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/acmeissuer.go","lineNumber":204,"sourceCode":"\t}\n\n\t// expand DNS override domain, if non-empty\n\tif iss.Challenges != nil && iss.Challenges.DNS != nil && iss.Challenges.DNS.OverrideDomain != \"\" {\n\t\toverrideDomain, err := repl.ReplaceOrErr(iss.Challenges.DNS.OverrideDomain, true, true)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"expanding DNS override domain '%s': %v\", iss.Challenges.DNS.OverrideDomain, err)\n\t\t}\n\t\tiss.Challenges.DNS.OverrideDomain = overrideDomain\n\t}\n\n\t// DNS challenge provider, if not already established\n\tif iss.Challenges != nil && iss.Challenges.DNS != nil && iss.Challenges.DNS.solver == nil {\n\t\tvar prov certmagic.DNSProvider\n\t\tif iss.Challenges.DNS.ProviderRaw != nil {\n\t\t\t// a challenge provider has been locally configured - use it\n\t\t\tval, err := ctx.LoadModule(iss.Challenges.DNS, \"ProviderRaw\")\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"loading DNS provider module: %v\", err)\n\t\t\t}\n\t\t\tprov = val.(certmagic.DNSProvider)\n\t\t} else if tlsAppIface, err := ctx.AppIfConfigured(\"tls\"); err == nil {\n\t\t\t// no locally configured DNS challenge provider, but if there is\n\t\t\t// a global DNS module configured with the TLS app, use that\n\t\t\ttlsApp := tlsAppIface.(*TLS)\n\t\t\tif tlsApp.dns != nil {\n\t\t\t\tprov = tlsApp.dns.(certmagic.DNSProvider)\n\t\t\t}\n\t\t}\n\t\tif prov == nil {\n\t\t\treturn fmt.Errorf(\"DNS challenge enabled, but no DNS provider configured\")\n\t\t}\n\t\tiss.Challenges.DNS.solver = &certmagic.DNS01Solver{\n\t\t\tDNSManager: certmagic.DNSManager{\n\t\t\t\tDNSProvider:        prov,\n\t\t\t\tTTL:                time.Duration(iss.Challenges.DNS.TTL),\n\t\t\t\tPropagationDelay:   time.Duration(iss.Challenges.DNS.PropagationDelay),","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/acmeissuer.go#L186-L222","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before: stock binary, no plugin\n example.com {\n   tls {\n     dns cloudflare {env.CF_API_TOKEN}\n   }\n }\n\n# after: build with the plugin, keep the config\nxcaddy build --with github.com/caddy-dns/cloudflare\n# then deploy the new binary; config unchanged","handlingStrategy":"validation","validationCode":"# confirm the provider module exists in the binary before deploying config\ncaddy list-modules | grep -q 'dns.providers.cloudflare' || {\n  echo \"cloudflare DNS plugin missing; rebuild with xcaddy\"; exit 1; }\n# and confirm credentials resolve\ntest -n \"$CF_API_TOKEN\" || { echo \"CF_API_TOKEN unset\"; exit 1; }","typeGuard":null,"tryCatchPattern":"if err := issuer.Provision(ctx); err != nil {\n    if strings.Contains(err.Error(), \"loading DNS provider module\") {\n        // unwrap for the real cause: missing plugin (rebuild) or bad creds (fix options)\n    }\n    return err\n}","preventionTips":["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"],"tags":["tls","acme","dns-challenge","plugin","xcaddy","credentials"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}