caddyserver/caddy · error
failed reading ca cert: %v
Error message
failed reading ca cert: %v
What it means
While building the http loader's TLS config, each file in tls.root_ca (RootCAPEMFiles) is read with os.ReadFile; any read failure (missing file, permission denied, path is a directory) is wrapped with this message. Note AppendCertsFromPEM's boolean result is not checked, so only the file-read step can error — a wrong-format-but-readable file fails later at handshake time instead.
Source
Thrown at caddyconfig/httploader.go:202
// See https://github.com/securego/gosec/issues/1054#issuecomment-2072235199
//nolint:gosec
tlsConfig = &tls.Config{Certificates: certs}
} else if hl.TLS.ClientCertificateFile != "" && hl.TLS.ClientCertificateKeyFile != "" {
cert, err := tls.LoadX509KeyPair(hl.TLS.ClientCertificateFile, hl.TLS.ClientCertificateKeyFile)
if err != nil {
return nil, err
}
//nolint:gosec
tlsConfig = &tls.Config{Certificates: []tls.Certificate{cert}}
}
// trusted server certs
if len(hl.TLS.RootCAPEMFiles) > 0 {
rootPool := x509.NewCertPool()
for _, pemFile := range hl.TLS.RootCAPEMFiles {
pemData, err := os.ReadFile(pemFile)
if err != nil {
return nil, fmt.Errorf("failed reading ca cert: %v", err)
}
rootPool.AppendCertsFromPEM(pemData)
}
if tlsConfig == nil {
tlsConfig = new(tls.Config)
}
tlsConfig.RootCAs = rootPool
}
client.Transport = &http.Transport{TLSClientConfig: tlsConfig}
}
return client, nil
}
var _ caddy.ConfigLoader = (*HTTPLoader)(nil)
View on GitHub (pinned to 50e54ee279)
Solutions
- Verify the path exists and is readable by the Caddy process: 'ls -l /path/ca.pem'.
- Fix the path or mount the file into the container at the configured location.
- Ensure permissions allow the runtime user to read the file.
- Confirm the file is PEM-formatted so the pool actually gets populated once readable.
Example fix
# before
http https://cfg.internal/config.json {
tls {
root_ca /etc/ssl/cfg-ca.crt # not mounted
}
}
# after
# docker run ... -v ./cfg-ca.crt:/etc/caddy/cfg-ca.pem ...
http https://cfg.internal/config.json {
tls {
root_ca /etc/caddy/cfg-ca.pem
}
} Defensive patterns
Strategy: validation
Validate before calling
for f in /etc/caddy/ca.pem; do test -r "$f" || echo "unreadable: $f"; done
Prevention
- Mount CA files read-only into containers at fixed paths and reference those paths.
- Add a startup check that all configured root_ca files exist and are readable by the Caddy user.
- Remember a readable-but-non-PEM file passes silently here and fails later at TLS handshake — verify format too.
When it happens
Trigger: tls { root_ca /path/that/does/not/exist.pem }; the CA file present but unreadable due to permissions or container mount issues; a path pointing at a directory.
Common situations: Docker/Kubernetes mounts that changed and dropped the CA file; running Caddy under a user without read access; absolute paths from another host copied verbatim.
Related errors
- problem calling http loader url: %v
- getting server identity credentials: %v
- cannot enable remote admin without a certificate cache; conf
- loading dynamic config from %T: %v
- consolidating TLS connection policies for server %d: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/e04924937b56fb48.
Report an issue: GitHub.