{"record":{"id":"675d8bb0d46a4953","repo":"joewalnes/websocketd","slug":"failed-to-parse-ca-certificates-from-s","errorCode":null,"errorMessage":"failed to parse CA certificates from %s","messagePattern":"failed to parse CA certificates from (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"main.go","lineNumber":112,"sourceCode":"}\n\n// tlsConfig returns the base TLS settings shared by all HTTPS servers. It pins\n// a minimum protocol version explicitly rather than relying on the Go default,\n// which has drifted across releases.\nfunc tlsConfig() *tls.Config {\n\treturn &tls.Config{MinVersion: tls.VersionTLS12}\n}\n\n// serveMutualTLS runs an HTTPS server on the given listener that requires\n// client certificates verified against the given CA file.\nfunc serveMutualTLS(listener net.Listener, certFile, keyFile, caFile string, log *libwebsocketd.LogScope) error {\n\tcaCert, err := os.ReadFile(caFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read CA file %s: %w\", caFile, err)\n\t}\n\tcaCertPool := x509.NewCertPool()\n\tif !caCertPool.AppendCertsFromPEM(caCert) {\n\t\treturn fmt.Errorf(\"failed to parse CA certificates from %s\", caFile)\n\t}\n\n\tcfg := tlsConfig()\n\tcfg.ClientAuth = tls.RequireAndVerifyClientCert\n\tcfg.ClientCAs = caCertPool\n\tserver := &http.Server{\n\t\tReadHeaderTimeout: readHeaderTimeout,\n\t\tTLSConfig:         cfg,\n\t}\n\tlog.Info(\"server\", \"Mutual TLS enabled (client certs verified against %s)\", caFile)\n\treturn server.ServeTLS(listener, certFile, keyFile)\n}\n\n// unixSocketProbeTimeout bounds the liveness probe against an existing socket\n// file. A local AF_UNIX connect either succeeds or is refused immediately; the\n// timeout only guards against a pathological listener that accepts nothing.\nconst unixSocketProbeTimeout = time.Second\n","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/joewalnes/websocketd/blob/7a8683dc7f9778dc615945aaed2a8dc77290227b/main.go#L94-L130","documentation":"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.","triggerScenarios":"--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.","commonSituations":"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).","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."],"exampleFix":"// before (DER file passed directly)\n--ssl-ca-file=/etc/pki/ca.der\n// after\nopenssl x509 -inform der -in /etc/pki/ca.der -out /etc/pki/ca.pem\n--ssl-ca-file=/etc/pki/ca.pem","handlingStrategy":"validation","validationCode":"import \"crypto/x509\", \"encoding/pem\", \"os\"\nfunc validPEMCertPool(path string) error {\n    data, err := os.ReadFile(path)\n    if err != nil { return err }\n    pool := x509.NewCertPool()\n    if !pool.AppendCertsFromPEM(data) {\n        return fmt.Errorf(\"%s contains no PEM certificates\", path)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := startServer(); err != nil {\n    if strings.Contains(err.Error(), \"failed to parse CA certificates\") {\n        log.Fatalf(\"CA bundle invalid — regenerate with: openssl x509 -inform der -in ca.der -out ca.pem\")\n    }\n    return err\n}","preventionTips":["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-----'."],"tags":["tls","mutual-tls","pem","certificate","configuration"],"backgroundTag":"invalid-pem-certificate","analyzedSha":"7a8683dc7f9778dc615945aaed2a8dc77290227b","analyzedAt":"2026-09-03T13:52:22.309Z","contentChangedAt":"2026-09-03T13:52:22.309Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}