caddyserver/caddy · error
failed to load system cert pool: %v
Error message
failed to load system cert pool: %v
What it means
The `tls.ca_pool.source.system` pool calls x509.SystemCertPool() to load the OS trust store, and that call failed. On most platforms this only fails when the system certificate store cannot be read or parsed at all.
Source
Thrown at modules/caddytls/capools.go:802
type SystemCAPool struct {
pool *x509.CertPool
}
// CaddyModule implements caddy.Module.
func (SystemCAPool) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "tls.ca_pool.source.system",
New: func() caddy.Module {
return new(SystemCAPool)
},
}
}
// Provision implements caddy.Provisioner.
func (scp *SystemCAPool) Provision(ctx caddy.Context) error {
pool, err := x509.SystemCertPool()
if err != nil {
return fmt.Errorf("failed to load system cert pool: %v", err)
}
scp.pool = pool
return nil
}
func (scp *SystemCAPool) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
d.Next() // consume module name
if d.CountRemainingArgs() > 0 {
return d.ArgErr()
}
if d.NextBlock(0) {
return d.Err("system trust pool does not support any configuration")
}
return nil
}
// CertPool implements CA.
func (scp SystemCAPool) CertPool() *x509.CertPool {View on GitHub (pinned to 50e54ee279)
Solutions
- In containers, install the CA certificates package (e.g. `apt-get install -ca-certificates` on Debian, `apk add ca-certificates` on Alpine) and rebuild.
- On hosts, rebuild the trust store (Debian: `update-ca-certificates --fresh`; RHEL: `update-ca-trust`).
- If the system store genuinely cannot be fixed, use an explicit `file` or `inline` trust pool instead of `system`.
Example fix
# before: Dockerfile FROM scratch COPY caddy /caddy # after: Dockerfile FROM alpine:3.20 RUN apk add --no-cache ca-certificates COPY caddy /usr/bin/caddy
Defensive patterns
Strategy: validation
Validate before calling
// container/CI check: system store readable and non-empty (unix)
import (
"crypto/x509"
"os"
)
func systemStoreOK() error {
if _, err := x509.SystemCertPool(); err != nil {
return fmt.Errorf("system cert pool unavailable: %w", err)
}
if _, err := os.Stat("/etc/ssl/certs"); os.IsNotExist(err) {
return errors.New("no /etc/ssl/certs; install ca-certificates")
}
return nil
} Prevention
- Base containers on images that include ca-certificates, or install it in the Dockerfile.
- Add a startup health check that loads the system pool before Caddy serves traffic.
- For immutable/minimal images, prefer explicit `file` trust pools over `system`.
When it happens
Trigger: The OS trust store is missing, empty, unreadable, or corrupt — e.g. a minimal container with no ca-certificates package, a broken /etc/ssl/certs, or unusual permissions on the trust store files.
Common situations: Docker/Distroless/scratch images without ca-certificates installed; chroots with incomplete /etc/ssl; broken symlinks in the cert directory after a partial update.
Related errors
- WebSocket connections aren't allowed.
- Disabling same-origin restrictions is not allowed.
- Buggy browser is sending null Origin header.
- syntax error: unexpected token '%s', expecting '%s', at %s:%
- --config is required
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/dc743523d62a57a4.
Report an issue: GitHub.