caddyserver/caddy · error
could not parse leaf certificates loaders: %s
Error message
could not parse leaf certificates loaders: %s
What it means
LeafCertClientAuth.Provision loads the raw modules under LeafCertificateLoadersRaw (the 'leaf certificate loaders' of the tls.client_auth.verifier.leaf module); if any fails to load or instantiate, the error is wrapped as 'could not parse leaf certificates loaders'. This is a config/module-loading failure, before any file is read.
Source
Thrown at modules/caddytls/connpolicy.go:971
LeafCertificateLoadersRaw []json.RawMessage `json:"leaf_certs_loaders,omitempty" caddy:"namespace=tls.leaf_cert_loader inline_key=loader"`
trustedLeafCerts []*x509.Certificate
}
// CaddyModule returns the Caddy module information.
func (LeafCertClientAuth) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "tls.client_auth.verifier.leaf",
New: func() caddy.Module { return new(LeafCertClientAuth) },
}
}
func (l *LeafCertClientAuth) Provision(ctx caddy.Context) error {
if l.LeafCertificateLoadersRaw == nil {
return nil
}
val, err := ctx.LoadModule(l, "LeafCertificateLoadersRaw")
if err != nil {
return fmt.Errorf("could not parse leaf certificates loaders: %s", err.Error())
}
trustedLeafCertloaders := []LeafCertificateLoader{}
for _, loader := range val.([]any) {
trustedLeafCertloaders = append(trustedLeafCertloaders, loader.(LeafCertificateLoader))
}
trustedLeafCertificates := []*x509.Certificate{}
for _, loader := range trustedLeafCertloaders {
certs, err := loader.LoadLeafCertificates()
if err != nil {
return fmt.Errorf("could not load leaf certificates: %s", err.Error())
}
trustedLeafCertificates = append(trustedLeafCertificates, certs...)
}
l.trustedLeafCerts = trustedLeafCertificates
return nil
}
// UnmarshalCaddyfile implements caddyfile.Unmarshaler.View on GitHub (pinned to 50e54ee279)
Solutions
- Check the loader module name and block syntax against the docs: 'inline' (leaf_cert inline <base64 der>) and 'file' (leaf_cert file <path>) are the stock loaders
- For JSON, ensure each entry is a module object with "loader": "inline" or "loader": "file"
- If a custom loader is referenced, confirm it is compiled in: caddy list-modules | grep tls.leaf_cert_loader
- Run caddy validate to get the underlying wrapped error detail
Defensive patterns
Strategy: validation
Validate before calling
// (shell) confirm loader modules exist before referencing them caddy list-modules | grep '^tls\.leaf_cert_loader\.' # expect: tls.leaf_cert_loader.file, tls.leaf_cert_loader.inline
Type guard
// For custom loaders: prove interface compliance at compile time var _ caddytls.LeafCertificateLoader = (*MyLoader)(nil)
Try / catch
if err := caddy.Run(cfg); err != nil {
if strings.Contains(err.Error(), "could not parse leaf certificates loaders") {
// inspect inner error: usually unknown module name or bad loader body
log.Printf("leaf loader config error: %v", err)
}
} Prevention
- Use Caddyfile form (verifier leaf { leaf_cert file ... }) instead of hand-written JSON where possible
- Run caddy validate after changing any client_auth verifier stanza
- Rebuild custom loaders with the same xcaddy build as the target Caddy version
When it happens
Trigger: Specifying verifier leaf { leaf_cert <name> { ... } } in a Caddyfile or the equivalent JSON where the loader module name is unknown or its body is malformed; a third-party loader module that fails its own Provision/Validate.
Common situations: Typos in the loader module name (e.g. 'file ' vs 'file', 'inline' misspelled); JSON hand-written with a wrong 'loader' key value; XCaddy plugin loaders missing from the build so the module ID is unresolvable.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- 'ca' module '%s' is not a certificate pool provider
- client auth mode not recognized: %s
- loading ECH DNS provider module: %v
- consolidating TLS connection policies for server %d: %v
- two policies with same match criteria have conflicting clien
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/3355a67d14070ee8.
Report an issue: GitHub.