caddyserver/caddy · error
ECH DNS provider module is not an ECH DNS Provider: %v
Error message
ECH DNS provider module is not an ECH DNS Provider: %v
What it means
After successfully loading the DNS provider module, ECHDNSPublisher type-asserts it to the ECHDNSProvider interface (GetRecords/SetRecords with context, i.e. libdns-style). If a module registers in the expected namespace but does not implement that interface, the assertion fails. Note a formatting quirk: the message interpolates err with %v, but err is nil at that point (the earlier LoadModule succeeded), so the message always ends with ': <nil>'. The failure itself means module-interface mismatch, effectively an internal/programming error.
Source
Thrown at modules/caddytls/ech.go:802
logger *zap.Logger
}
// CaddyModule returns the Caddy module information.
func (ECHDNSPublisher) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "tls.ech.publishers.dns",
New: func() caddy.Module { return new(ECHDNSPublisher) },
}
}
func (dnsPub *ECHDNSPublisher) Provision(ctx caddy.Context) error {
dnsProvMod, err := ctx.LoadModule(dnsPub, "ProviderRaw")
if err != nil {
return fmt.Errorf("loading ECH DNS provider module: %v", err)
}
prov, ok := dnsProvMod.(ECHDNSProvider)
if !ok {
return fmt.Errorf("ECH DNS provider module is not an ECH DNS Provider: %v", err)
}
dnsPub.provider = prov
dnsPub.logger = ctx.Logger()
return nil
}
// PublisherKey returns the name of the DNS provider module.
// We intentionally omit specific provider configuration (or a hash thereof,
// since the config is likely sensitive, potentially containing an API key)
// because it is unlikely that specific configuration, such as an API key,
// is relevant to unique key use as an ECH config publisher.
func (dnsPub ECHDNSPublisher) PublisherKey() string {
return string(dnsPub.provider.(caddy.Module).CaddyModule().ID)
}
// PublishECHConfigList publishes the given ECH config list (as binary) to the given DNS names.
// If there is an error, it may be of type PublishECHConfigListErrors, detailing
// potentially multiple errors keyed by associated innerName.View on GitHub (pinned to 50e54ee279)
Solutions
- Use the standard/bundled DNS provider modules, which are interface-guarded at compile time.
- For custom builds, align the libdns version so the provider implements the same GetRecords(context.Context, string)/SetRecords signatures Caddy compiles against.
- Rebuild with xcaddy so all modules compile against one libdns version.
Defensive patterns
Strategy: type-guard
Type guard
// Compile-time guard (works for custom builds): ensure your provider satisfies the interface. var _ caddytls.ECHDNSProvider = (*mylibdns.Provider)(nil)
Prevention
- Prefer bundled DNS providers; they are compile-time checked.
- Keep libdns versions aligned across all modules in xcaddy builds.
- Add interface guards in custom provider packages so mismatches fail at build time, not runtime.
When it happens
Trigger: A custom or third-party module registered as the dns provider for ECH publishing that implements a different RecordGetter/RecordSetter shape than libdns expects; only possible with custom builds — the bundled providers all implement the interface.
Common situations: Custom xcaddy builds pulling an incompatible libdns provider version (major API change in libdns.ZoneRecorder interfaces across versions).
Related errors
- loading ECH DNS provider module: %v
- could not determine zone for domain: %w (domain=%s nameserve
- unable to get existing DNS records to publish ECH data to HT
- unable to publish ECH data to HTTPS DNS record: %w (zone=%s
- public name length (%d) must be in the range 1-255
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/f61ad55bd71dacdf.
Report an issue: GitHub.