{"record":{"id":"d8c445aeeff774e4","repo":"crowdsecurity/crowdsec","slug":"failed-to-read-ca-cert-file-s-w","errorCode":null,"errorMessage":"failed to read CA cert file %s: %w","messagePattern":"failed to read CA cert file (.+?): %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/csconfig/database.go","lineNumber":170,"sourceCode":"\t\tif systemRootCAs != nil {\n\t\t\ttlsConfig.RootCAs = systemRootCAs\n\t\t}\n\n\t\tif d.isSocketConfig() {\n\t\t\tconnString = fmt.Sprintf(\"%s:%s@unix(%s)/%s\", d.User, d.Password, d.DbPath, d.DbName)\n\t\t} else {\n\t\t\tconnString = fmt.Sprintf(\"%s:%s@tcp(%s:%d)/%s\", d.User, d.Password, d.Host, d.Port, d.DbName)\n\t\t}\n\n\t\tif d.SSLMode != \"\" {\n\t\t\t// This will be overridden if a CA or client cert is provided\n\t\t\tparams.Set(\"tls\", d.SSLMode)\n\t\t}\n\n\t\tif d.SSLCACert != \"\" {\n\t\t\tcaCert, err := os.ReadFile(d.SSLCACert)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"failed to read CA cert file %s: %w\", d.SSLCACert, err)\n\t\t\t}\n\t\t\tif tlsConfig.RootCAs == nil {\n\t\t\t\ttlsConfig.RootCAs = x509.NewCertPool()\n\t\t\t}\n\t\t\tif !tlsConfig.RootCAs.AppendCertsFromPEM(caCert) {\n\t\t\t\treturn \"\", fmt.Errorf(\"failed to append CA cert file %s: %w\", d.SSLCACert, err)\n\t\t\t}\n\t\t\tparams.Set(\"tls\", \"custom\")\n\t\t}\n\n\t\tif d.SSLClientCert != \"\" && d.SSLClientKey != \"\" {\n\t\t\tcert, err := tls.LoadX509KeyPair(d.SSLClientCert, d.SSLClientKey)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"failed to load client cert/key pair: %w\", err)\n\t\t\t}\n\t\t\ttlsConfig.Certificates = []tls.Certificate{cert}\n\t\t\tparams.Set(\"tls\", \"custom\")\n\t\t}","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/csconfig/database.go#L152-L188","documentation":"For MySQL connections, ConnectionString reads the configured SSL CA certificate (db_config.ssl_ca_cert) with os.ReadFile to build the TLS RootCAs pool. Any read failure is wrapped as 'failed to read CA cert file %s: %w'. This runs whenever a MySQL connection string is built (e.g. NewClient at startup or `cscli` commands).","triggerScenarios":"Database config sets ssl_ca_cert to a path that does not exist, is unreadable (permissions), or is a directory.","commonSituations":"Typo in ssl_ca_cert path; cert file deleted during rotation; running cscli as a user who cannot read the root-owned CA file; relative path resolved from wrong working directory.","solutions":["Verify the ssl_ca_cert path exists and is readable by the crowdsec/cscli user (`ls -l`, `cat` the file)","Use an absolute path in db_config.ssl_ca_cert","If the CA file was rotated, restore/redeploy it or update the path"],"exampleFix":"// before\nssl_ca_cert: ./ca.pem\n// after\nssl_ca_cert: /etc/crowdsec/db/ca.pem","handlingStrategy":"validation","validationCode":"if _, err := os.ReadFile(sslCACert); err != nil { return fmt.Errorf(\"ssl_ca_cert %q unreadable: %w\", sslCACert, err) }","typeGuard":null,"tryCatchPattern":"connStr, err := dbCfg.ConnectionString(); if err != nil { log.Fatalf(\"db connection string failed (check ssl_ca_cert path): %v\", err) }","preventionTips":["Use absolute paths for ssl_ca_cert","Verify cert existence/readability with `ls -l` before startup, and after cert rotation","Ensure cscli/crowdsec run as a user that can read the CA file"],"tags":["database","mysql","tls","filesystem"],"backgroundTag":"file-not-found","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}