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

  1. Use the standard/bundled DNS provider modules, which are interface-guarded at compile time.
  2. For custom builds, align the libdns version so the provider implements the same GetRecords(context.Context, string)/SetRecords signatures Caddy compiles against.
  3. 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

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


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/f61ad55bd71dacdf. Report an issue: GitHub.