caddyserver/caddy · error
no CERTIFICATE pem block found in %s
Error message
no CERTIFICATE pem block found in %s
What it means
Returned by convertPEMFilesToDER, used when a Caddyfile trusted_ca_cert_file (or trusted_leaf_cert_file) is read: the file was read successfully but contains either zero PEM blocks or a block whose type is not CERTIFICATE (e.g. a private key or a CSR). The filename in the message identifies the offending file.
Source
Thrown at modules/caddytls/connpolicy.go:764
if len(ca.TrustedCACerts) > 0 {
fileMod := &InlineCAPool{}
fileMod.TrustedCACerts = append(fileMod.TrustedCACerts, ca.TrustedCACerts...)
ca.CARaw = caddyconfig.JSONModuleObject(fileMod, "provider", "inline", nil)
ca.TrustedCACertPEMFiles, ca.TrustedCACerts = nil, nil
}
return nil
}
func convertPEMFilesToDER(filename string) ([]string, error) {
certDataPEM, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
var ders []string
// while block is not nil, we have more certificates in the file
for block, rest := pem.Decode(certDataPEM); block != nil; block, rest = pem.Decode(rest) {
if block.Type != "CERTIFICATE" {
return nil, fmt.Errorf("no CERTIFICATE pem block found in %s", filename)
}
ders = append(
ders,
base64.StdEncoding.EncodeToString(block.Bytes),
)
}
// if we decoded nothing, return an error
if len(ders) == 0 {
return nil, fmt.Errorf("no CERTIFICATE pem block found in %s", filename)
}
return ders, nil
}
func (clientauth *ClientAuthentication) provision(ctx caddy.Context) error {
if len(clientauth.CARaw) > 0 && (len(clientauth.TrustedCACerts) > 0 || len(clientauth.TrustedCACertPEMFiles) > 0) {
return fmt.Errorf("conflicting config for client authentication trust CA")
}
View on GitHub (pinned to 50e54ee279)
Solutions
- Inspect the file: 'openssl x509 -in <file> -text -noout' should parse it as PEM (or grep for BEGIN CERTIFICATE)
- If it is DER, convert: 'openssl x509 -inform der -in cert.der -out cert.pem'
- Remove any PRIVATE KEY or other non-certificate blocks from the file
- Re-download the CA bundle if it is empty or truncated
Example fix
# before
client_auth {
trusted_ca_cert_file /etc/candy/ca.pem # typo'd dir -> empty file
}
# after
client_auth {
trusted_ca_cert_file /etc/caddy/ca.pem
} Defensive patterns
Strategy: validation
Validate before calling
# Validate a CA file before referencing it in config: openssl x509 -in /etc/caddy/ca.pem -noout >/dev/null 2>&1 \ && echo OK || echo "not a PEM certificate file"
Prevention
- Feed trusted_ca_cert_file only CA bundles in PEM format (BEGIN CERTIFICATE blocks)
- Convert DER to PEM with openssl x509 -inform der before use
- Never point this directive at key files, CSRs, or full server chains with mixed block types
- Add a CI check that greps referenced cert files for 'BEGIN CERTIFICATE'
When it happens
Trigger: Pointing trusted_ca_cert_file at: an empty file, a DER (binary) certificate instead of PEM, a file containing a PRIVATE KEY block, or a file with only non-CERTIFICATE PEM blocks. Every block in the file must be a CERTIFICATE block.
Common situations: Operator passes the server's fullchain.pem where a CA bundle was expected and it still parses until a non-cert block appears; file is actually DER-encoded; file truncated to zero bytes by a failed provisioner; correct path but wrong file (key file).
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- parsing certificate in %s: %v
- loading certificates: %v
- two policies with same match criteria have conflicting clien
- two policies with same match criteria have conflicting cert
- finalizing automatic HTTPS: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/3d0bcb1a582c91f7.
Report an issue: GitHub.