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

  1. 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
  2. For JSON, ensure each entry is a module object with "loader": "inline" or "loader": "file"
  3. If a custom loader is referenced, confirm it is compiled in: caddy list-modules | grep tls.leaf_cert_loader
  4. 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

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

Related errors


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