caddyserver/caddy · error

'ca' module '%s' is not a certificate pool provider

Error message

'ca' module '%s' is not a certificate pool provider

What it means

ClientAuthentication.provision loads the module named in the 'ca' field of client authentication and asserts it implements the caddytls CA interface (a certificate pool provider). If the loaded module does not implement CertPool(), provisioning fails. Note the message formats the module value with %s, so the detail printed may be unhelpful (the module's String form or %!s(...) artifact) — a known cosmetic quirk of this line.

Source

Thrown at modules/caddytls/connpolicy.go:816

		}
		err := caPool.Provision(ctx)
		if err != nil {
			return err
		}
		clientauth.ca = caPool
	}

	// if we don't have any CARaw set, there's not much work to do
	if clientauth.CARaw == nil {
		return nil
	}
	caRaw, err := ctx.LoadModule(clientauth, "CARaw")
	if err != nil {
		return err
	}
	ca, ok := caRaw.(CA)
	if !ok {
		return fmt.Errorf("'ca' module '%s' is not a certificate pool provider", ca)
	}
	clientauth.ca = ca

	return nil
}

// Active returns true if clientauth has an actionable configuration.
func (clientauth ClientAuthentication) Active() bool {
	return len(clientauth.TrustedCACerts) > 0 ||
		len(clientauth.TrustedCACertPEMFiles) > 0 ||
		len(clientauth.TrustedLeafCerts) > 0 || // TODO: DEPRECATED
		len(clientauth.VerifiersRaw) > 0 ||
		len(clientauth.Mode) > 0 ||
		clientauth.CARaw != nil || clientauth.ca != nil
}

// ConfigureTLSConfig sets up cfg to enforce clientauth's configuration.
func (clientauth *ClientAuthentication) ConfigureTLSConfig(cfg *tls.Config) error {

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Set 'ca' to a module that actually provides a certificate pool (e.g. the internal PKI CA: ca internal)
  2. If this is your own XCaddy plugin, make the type implement CertPool() *x509.CertPool and re-check the interface guard var _ CA = (*YourCA)(nil)
  3. Verify the module ID you typed is registered: caddy list-modules | grep tls.ca
  4. If you do not need a module-based CA, drop 'ca' and use trusted_ca_certs_file instead
Defensive patterns

Strategy: type-guard

Validate before calling

// List candidate CA modules and confirm the ID exists before writing config
// (shell) caddy list-modules | grep '^tls\.ca\.'

Type guard

// For plugin authors: compile-time guarantee your module satisfies the CA interface
var _ caddytls.CA = (*MyCAPoolProvider)(nil)

func (m *MyCAPoolProvider) CertPool() *x509.CertPool { /* ... */ return nil }

Prevention

When it happens

Trigger: Setting "ca": {"module": "..."} under client_authentication to a module ID that exists but is not a CA pool provider, or a custom plugin registered under the wrong namespace; typically unreachable with stock modules unless a third-party module is misregistered.

Common situations: Third-party XCaddy plugins that register a module under tls.ca without implementing the CA interface; typos in a custom module namespace; upgrading a plugin that changed its implemented interfaces.

Understand the failure class

Related errors


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