caddyserver/caddy · error
DNS module does not implement the most common libdns interfa
Error message
DNS module does not implement the most common libdns interfaces: %T
What it means
The configured global DNS provider loaded successfully but its type does not simultaneously implement libdns.RecordAppender, RecordDeleter, RecordGetter, and RecordSetter. Caddy requires the most common libdns interfaces because the same provider instance may be used for ACME DNS challenges, on-demand cert management, and DNS record manipulation. This is a compile-time property of the module's Go type, so it indicates an incompatible or incomplete plugin.
Source
Thrown at modules/caddytls/tls.go:191
t.serverNamesMu = new(sync.Mutex)
// set up default DNS module, if any, and make sure it implements all the
// common libdns interfaces, since it could be used for a variety of things
// (do this before provisioning other modules, since they may rely on this)
if len(t.DNSRaw) > 0 {
dnsMod, err := ctx.LoadModule(t, "DNSRaw")
if err != nil {
return fmt.Errorf("loading overall DNS provider module: %v", err)
}
switch dnsMod.(type) {
case interface {
libdns.RecordAppender
libdns.RecordDeleter
libdns.RecordGetter
libdns.RecordSetter
}:
default:
return fmt.Errorf("DNS module does not implement the most common libdns interfaces: %T", dnsMod)
}
t.dns = dnsMod
}
// set up a new certificate cache; this (re)loads all certificates
cacheOpts := certmagic.CacheOptions{
GetConfigForCert: func(cert certmagic.Certificate) (*certmagic.Config, error) {
return t.getConfigForName(cert.Names[0]), nil
},
Logger: t.logger.Named("cache"),
}
if t.Automation != nil {
cacheOpts.OCSPCheckInterval = time.Duration(t.Automation.OCSPCheckInterval)
cacheOpts.RenewCheckInterval = time.Duration(t.Automation.RenewCheckInterval)
}
if t.Cache != nil {
cacheOpts.Capacity = t.Cache.Capacity
}View on GitHub (pinned to 50e54ee279)
Solutions
- Update the DNS plugin to a release compatible with your Caddy version (interfaces must match current libdns)
- Rebuild with xcaddy so plugin and core resolve to one consistent libdns version: 'xcaddy build --with github.com/caddy-dns/<provider>@latest'
- If you maintain the module, implement all four interfaces: RecordAppender, RecordDeleter, RecordGetter, RecordSetter
Example fix
// before: plugin only implements GetRecords/AppendRecords
// after: add the missing methods to satisfy all interfaces
type Provider struct{}
func (p *Provider) GetRecords(ctx context.Context, zone string) ([]libdns.Record, error) { ... }
func (p *Provider) AppendRecords(ctx context.Context, zone string, recs []libdns.Record) ([]libdns.Record, error) { ... }
func (p *Provider) DeleteRecords(ctx context.Context, zone string, recs []libdns.Record) ([]libdns.Record, error) { ... }
func (p *Provider) SetRecords(ctx context.Context, zone string, recs []libdns.Record) ([]libdns.Record, error) { ... } Defensive patterns
Strategy: validation
Validate before calling
go build ./... && go vet ./... # in the plugin repo
# compile-time guard inside a custom DNS module:
var _ interface {
libdns.RecordAppender
libdns.RecordDeleter
libdns.RecordGetter
libdns.RecordSetter
} = (*Provider)(nil) Type guard
func implementsCommonLibdns(p any) bool {
switch p.(type) {
case interface {
libdns.RecordAppender
libdns.RecordDeleter
libdns.RecordGetter
libdns.RecordSetter
}:
return true
}
return false
} Prevention
- Add the four-interface compile-time guard in any custom DNS module
- Update plugins and Caddy together via xcaddy so one libdns version is resolved
When it happens
Trigger: Configuring tls.dns with a module that only implements a narrower interface set (e.g. a challenge-only shim that implements just dns01solver.Provider, or a libdns plugin pinned to an old libdns API version where method signatures changed). The type switch at tls.go:185 fails for that Go type.
Common situations: A third-party DNS plugin built against an older github.com/libdns/libdns major version (interface signatures changed) and compiled with xcaddy against a newer Caddy; hand-written DNS provider modules that omit one of the four record methods.
Related errors
- --config is required
- the 'forwarded' option is no longer supported; use the 'clie
- converting hostname '%s' to ASCII: %v
- decoded module is not a RequestMatcher or RequestMatcherWith
- loading overall DNS provider module: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/5c8fdb4a2faeb07a.
Report an issue: GitHub.