{"record":{"id":"5c8fdb4a2faeb07a","repo":"caddyserver/caddy","slug":"dns-module-does-not-implement-the-most-common-libd","errorCode":null,"errorMessage":"DNS module does not implement the most common libdns interfaces: %T","messagePattern":"DNS module does not implement the most common libdns interfaces: %T","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/tls.go","lineNumber":191,"sourceCode":"\tt.serverNamesMu = new(sync.Mutex)\n\n\t// set up default DNS module, if any, and make sure it implements all the\n\t// common libdns interfaces, since it could be used for a variety of things\n\t// (do this before provisioning other modules, since they may rely on this)\n\tif len(t.DNSRaw) > 0 {\n\t\tdnsMod, err := ctx.LoadModule(t, \"DNSRaw\")\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"loading overall DNS provider module: %v\", err)\n\t\t}\n\t\tswitch dnsMod.(type) {\n\t\tcase interface {\n\t\t\tlibdns.RecordAppender\n\t\t\tlibdns.RecordDeleter\n\t\t\tlibdns.RecordGetter\n\t\t\tlibdns.RecordSetter\n\t\t}:\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"DNS module does not implement the most common libdns interfaces: %T\", dnsMod)\n\t\t}\n\t\tt.dns = dnsMod\n\t}\n\n\t// set up a new certificate cache; this (re)loads all certificates\n\tcacheOpts := certmagic.CacheOptions{\n\t\tGetConfigForCert: func(cert certmagic.Certificate) (*certmagic.Config, error) {\n\t\t\treturn t.getConfigForName(cert.Names[0]), nil\n\t\t},\n\t\tLogger: t.logger.Named(\"cache\"),\n\t}\n\tif t.Automation != nil {\n\t\tcacheOpts.OCSPCheckInterval = time.Duration(t.Automation.OCSPCheckInterval)\n\t\tcacheOpts.RenewCheckInterval = time.Duration(t.Automation.RenewCheckInterval)\n\t}\n\tif t.Cache != nil {\n\t\tcacheOpts.Capacity = t.Cache.Capacity\n\t}","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/tls.go#L173-L209","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: plugin only implements GetRecords/AppendRecords\n// after: add the missing methods to satisfy all interfaces\ntype Provider struct{}\n\nfunc (p *Provider) GetRecords(ctx context.Context, zone string) ([]libdns.Record, error) { ... }\nfunc (p *Provider) AppendRecords(ctx context.Context, zone string, recs []libdns.Record) ([]libdns.Record, error) { ... }\nfunc (p *Provider) DeleteRecords(ctx context.Context, zone string, recs []libdns.Record) ([]libdns.Record, error) { ... }\nfunc (p *Provider) SetRecords(ctx context.Context, zone string, recs []libdns.Record) ([]libdns.Record, error) { ... }","handlingStrategy":"validation","validationCode":"go build ./... && go vet ./...  # in the plugin repo\n# compile-time guard inside a custom DNS module:\nvar _ interface {\n\tlibdns.RecordAppender\n\tlibdns.RecordDeleter\n\tlibdns.RecordGetter\n\tlibdns.RecordSetter\n} = (*Provider)(nil)","typeGuard":"func implementsCommonLibdns(p any) bool {\n\tswitch p.(type) {\n\tcase interface {\n\t\tlibdns.RecordAppender\n\t\tlibdns.RecordDeleter\n\t\tlibdns.RecordGetter\n\t\tlibdns.RecordSetter\n\t}:\n\t\treturn true\n\t}\n\treturn false\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["caddy","dns","libdns","interfaces","version-mismatch"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}