caddyserver/caddy · error

provisioning client CA: %v

Error message

provisioning client CA: %v

What it means

Returned by buildStandardTLSConfig when ClientAuthentication.provision fails while setting up client certificate verification for a connection policy. The wrapped error comes from provisioning the trust pool / verifier modules — e.g. loading the CA provider module (file, inline, combined) or parsing its inputs.

Source

Thrown at modules/caddytls/connpolicy.go:383

	if !alpnFound && (cfg.NextProtos == nil || len(cfg.NextProtos) > 0) {
		cfg.NextProtos = append(cfg.NextProtos, acmez.ACMETLS1Protocol)
	}

	// min and max protocol versions
	if (p.ProtocolMin != "" && p.ProtocolMax != "") && p.ProtocolMin > p.ProtocolMax {
		return fmt.Errorf("protocol min (%x) cannot be greater than protocol max (%x)", p.ProtocolMin, p.ProtocolMax)
	}
	if p.ProtocolMin != "" {
		cfg.MinVersion = SupportedProtocols[p.ProtocolMin]
	}
	if p.ProtocolMax != "" {
		cfg.MaxVersion = SupportedProtocols[p.ProtocolMax]
	}

	// client authentication
	if p.ClientAuthentication != nil {
		if err := p.ClientAuthentication.provision(ctx); err != nil {
			return fmt.Errorf("provisioning client CA: %v", err)
		}
		if err := p.ClientAuthentication.ConfigureTLSConfig(cfg); err != nil {
			return fmt.Errorf("configuring TLS client authentication: %v", err)
		}

		// Prevent privilege escalation in case multiple vhosts are configured for
		// this TLS server; we could potentially figure out if that's the case, but
		// that might be complex to get right every time. Actually, two proper
		// solutions could leave tickets enabled, but I am not sure how to do them
		// properly without significant time investment; there may be new Go
		// APIs that alloaw this (Wrap/UnwrapSession?) but I do not know how to use
		// them at this time. TODO: one of these is a possible future enhancement:
		// A) Prevent resumptions across server identities (certificates): binding the ticket to the
		// certificate we would serve in a full handshake, or even bind a ticket to the exact SNI
		// it was issued under (though there are proposals for session resumption across hostnames).
		// B) Prevent resumptions falsely authenticating a client: include the realm in the ticket,
		// so that it can be validated upon resumption.
		cfg.SessionTicketsDisabled = true

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Unwrap the inner error: it names the provider and the underlying failure
  2. Verify the CA file path exists and is readable by the caddy process (container volume mounts!)
  3. Confirm the file is a valid chain of CA certificates in PEM
  4. Check the trust_pool module name is one caddy list-modules shows under tls.ca_pool.source

Example fix

# before (path wrong inside container)
client_auth {
	trust_pool file /etc/ssl/client-ca.pem
}

# after (correct mounted path)
client_auth {
	trust_pool file /etc/caddy/client-ca.pem
}
Defensive patterns

Strategy: try-catch

Validate before calling

# Pre-flight file checks for trust_pool file paths:
for f in /etc/caddy/ca.pem; do
  [ -s "$f" ] && grep -q 'BEGIN CERTIFICATE' "$f" || echo "bad CA file: $f"
done

Prevention

When it happens

Trigger: A client_auth block whose trust_pool provider fails to provision: unreadable CA file path, malformed PEM, failing inline base64, or an unknown provider module. Also a verifier module failing its own Provision.

Common situations: CA file mounted at a different path in a container; PEM file containing a private key or wrong block type instead of CA certs; typo in the trust_pool provider name; permissions on the file.

Related errors


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