caddyserver/caddy · error

source %T does not implement CertificateProvider (required f

Error message

source %T does not implement CertificateProvider (required for combining)

What it means

Every source inside a combined CA pool must also implement the optional CertificateProvider interface (Certificates() []*x509.Certificate) so the combined pool can enumerate and merge the underlying certs. A source that only implements CA cannot be combined and triggers this error.

Source

Thrown at modules/caddytls/capools.go:873

	// Load all source modules
	sources, err := ctx.LoadModule(ccp, "SourcesRaw")
	if err != nil {
		return fmt.Errorf("loading CA pool sources: %v", err)
	}

	caPool := x509.NewCertPool()
	var allCerts []*x509.Certificate

	for _, src := range sources.([]any) {
		ca, ok := src.(CA)
		if !ok {
			return fmt.Errorf("source module is not a CA pool provider")
		}
		ccp.sources = append(ccp.sources, ca)

		certProvider, ok := ca.(CertificateProvider)
		if !ok {
			return fmt.Errorf("source %T does not implement CertificateProvider (required for combining)", ca)
		}

		certs := certProvider.Certificates()
		if certs == nil {
			return fmt.Errorf("source %T returned nil certificates", ca)
		}
		for _, cert := range certs {
			if cert == nil {
				return fmt.Errorf("source %T returned a nil certificate", ca)
			}
			caPool.AddCert(cert)
			allCerts = append(allCerts, cert)
		}
	}

	ccp.pool = caPool
	ccp.certs = allCerts

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Update the custom/plugin pool module to implement Certificates() []*x509.Certificate alongside CertPool().
  2. Alternatively, do not use that module inside a combined pool — reference it directly as the trust pool.
  3. Check the plugin's repo for a newer release matching your Caddy version.

Example fix

// before
type MyPool struct{}
func (m MyPool) CertPool() *x509.CertPool { return m.pool }

// after
type MyPool struct{ pool *x509.CertPool; certs []*x509.Certificate }
func (m MyPool) CertPool() *x509.CertPool { return m.pool }
func (m MyPool) Certificates() []*x509.Certificate { return m.certs }
Defensive patterns

Strategy: type-guard

Type guard

// compile-time guarantee that a custom pool satisfies both interfaces
var (
	_ caddytls.CA                 = (*MyPool)(nil)
	_ caddytls.CertificateProvider = (*MyPool)(nil)
)

Prevention

When it happens

Trigger: Embedding a third-party or custom CA pool module that implements CertPool() but not Certificates() and using it as a source of a combined pool. All built-in pools implement both, so this is a custom-module issue.

Common situations: Plugin modules written against an older API surface; custom pool sources written without the CertificateProvider method.

Understand the failure class

Related errors


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