joewalnes/websocketd · critical
failed to parse CA certificates from %s
Error message
failed to parse CA certificates from %s
What it means
The CA file was readable but x509.AppendCertsFromPEM parsed no certificates out of it, so websocketd cannot build a ClientCAs pool and refuses to start mutual TLS with this error. AppendCertsFromPEM only reports false when the data contains zero usable certificates.
Source
Thrown at main.go:112
}
// tlsConfig returns the base TLS settings shared by all HTTPS servers. It pins
// a minimum protocol version explicitly rather than relying on the Go default,
// which has drifted across releases.
func tlsConfig() *tls.Config {
return &tls.Config{MinVersion: tls.VersionTLS12}
}
// serveMutualTLS runs an HTTPS server on the given listener that requires
// client certificates verified against the given CA file.
func serveMutualTLS(listener net.Listener, certFile, keyFile, caFile string, log *libwebsocketd.LogScope) error {
caCert, err := os.ReadFile(caFile)
if err != nil {
return fmt.Errorf("failed to read CA file %s: %w", caFile, err)
}
caCertPool := x509.NewCertPool()
if !caCertPool.AppendCertsFromPEM(caCert) {
return fmt.Errorf("failed to parse CA certificates from %s", caFile)
}
cfg := tlsConfig()
cfg.ClientAuth = tls.RequireAndVerifyClientCert
cfg.ClientCAs = caCertPool
server := &http.Server{
ReadHeaderTimeout: readHeaderTimeout,
TLSConfig: cfg,
}
log.Info("server", "Mutual TLS enabled (client certs verified against %s)", caFile)
return server.ServeTLS(listener, certFile, keyFile)
}
// unixSocketProbeTimeout bounds the liveness probe against an existing socket
// file. A local AF_UNIX connect either succeeds or is refused immediately; the
// timeout only guards against a pathological listener that accepts nothing.
const unixSocketProbeTimeout = time.Second
View on GitHub (pinned to 7a8683dc7f)
Solutions
- Inspect the file: it must contain PEM blocks starting with '-----BEGIN CERTIFICATE-----'; convert DER with `openssl x509 -inform der -in ca.der -out ca.pem`.
- Verify content sanity with `openssl x509 -in ca.pem -noout -text` and re-export the file if it's empty or truncated.
- Make sure the CA certificate, not a private key or server cert, is configured for --ssl-ca-file.
- If chaining, concatenate each CA as PEM blocks with proper newlines between them.
Example fix
// before (DER file passed directly) --ssl-ca-file=/etc/pki/ca.der // after openssl x509 -inform der -in /etc/pki/ca.der -out /etc/pki/ca.pem --ssl-ca-file=/etc/pki/ca.pem
Defensive patterns
Strategy: validation
Validate before calling
import "crypto/x509", "encoding/pem", "os"
func validPEMCertPool(path string) error {
data, err := os.ReadFile(path)
if err != nil { return err }
pool := x509.NewCertPool()
if !pool.AppendCertsFromPEM(data) {
return fmt.Errorf("%s contains no PEM certificates", path)
}
return nil
} Try / catch
if err := startServer(); err != nil {
if strings.Contains(err.Error(), "failed to parse CA certificates") {
log.Fatalf("CA bundle invalid — regenerate with: openssl x509 -inform der -in ca.der -out ca.pem")
}
return err
} Prevention
- Pre-flight the CA with `openssl x509 -in ca.pem -noout -text` in CI or entrypoint scripts.
- Never point --ssl-ca-file at a private key or the server cert.
- Convert DER to PEM before use; ensure exported files end with a newline.
- After generating a bundle, assert it starts with '-----BEGIN CERTIFICATE-----'.
When it happens
Trigger: --ssl-ca-file points at a DER-encoded cert (not PEM), an empty or truncated file, a key/private-key file passed instead of a certificate, concatenated junk/garbage, or a file containing only intermediate certs in an unreadable encoding.
Common situations: Downloading a CA from a portal that serves DER by default; redirecting the wrong variable into the file (echo $KEY > ca.pem); file truncated by a failed secret mount; mixing up --ssl-ca-file (client-verification CA) with --ssl-cert (server cert).
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to read CA file %s: %w
- please specify both --sslcert and --sslkey when requesting -
- you should not be using --ssl* flags when there is no --ssl
- ambiguous: provided COMMAND and --dir argument, please only
- did you mean to specify COMMAND instead of --dir '%s'?
AI-assisted analysis of joewalnes/websocketd@7a8683dc7f (2026-09-03).
Data as JSON: /api/errors/675d8bb0d46a4953.
Report an issue: GitHub.