caddyserver/caddy · error

loading ECH DNS provider module: %v

Error message

loading ECH DNS provider module: %v

What it means

The tls.ech.publishers.dns module (ECHDNSPublisher) embeds a pluggable DNS provider module loaded at provision time via ctx.LoadModule(dnsPub, "ProviderRaw"). This error wraps a module-load failure: the provider name in the config does not resolve to a registered module, or the provider module itself failed its own provisioning (bad credentials, invalid options). The message chains the underlying error.

Source

Thrown at modules/caddytls/ech.go:798

	ProviderRaw json.RawMessage `json:"provider,omitempty" caddy:"namespace=dns.providers inline_key=name"`
	provider    ECHDNSProvider

	alpnByDomain map[string][]string
	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)
}

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Read the wrapped (%v) cause — it usually names the exact module problem (unrecognized name or provider-specific provisioning error).
  2. Fix the provider module name in config to match a registered tls DNS provider module.
  3. Supply/refresh the provider credentials and options.
  4. If the provider isn't in the build, use a Caddy build that includes it (xcaddy build with the libdns provider package imported).

Example fix

// before
{"provider":{"name":"cloudflaredns","api_token":"..."}}

// after: match the registered module namespace
{"provider":{"name":"cloudflare","api_token":"..."}}
Defensive patterns

Strategy: validation

Validate before calling

// Validate provider module name against registered modules before load.
prov := cfg.Provider // caddy.Module etc.
if prov.Name == "" || !knownECHDNSProvider(prov.Name) {
    return fmt.Errorf("unknown ECH DNS provider: %q", prov.Name)
}

Try / catch

if err != nil && strings.Contains(err.Error(), "loading ECH DNS provider module") {
    // unwrap %v cause: unknown module name or provider provisioning failure
    return fmt.Errorf("fix ECH DNS provider config: %w", err)
}

Prevention

When it happens

Trigger: Config with tls.ech.publisher.dns whose provider is unknown (typo'd module name), a provider built without its build tag or not compiled into the binary, or a provider whose Provision rejects options (bad API token format, missing zone credentials).

Common situations: JSON config referencing a libdns provider that is not in the standard build; typo like "providers": {"clouddns": ...} vs actual module namespace; rotated/expired DNS provider API token causing the provider's own provisioning to fail; using a custom Caddy build that omitted the provider import.

Related errors


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