{"record":{"id":"0df76cbb6b43b3d7","repo":"router-for-me/CLIProxyAPI","slug":"home-tls-ca-cert-contains-no-pem-certificates","errorCode":null,"errorMessage":"home tls: ca-cert contains no PEM certificates","messagePattern":"home tls: ca-cert contains no PEM certificates","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/home/client.go","lineNumber":661,"sourceCode":"\t\ttlsConfig.Certificates = []tls.Certificate{certPair}\n\t}\n\n\tcaCertPath := strings.TrimSpace(cfg.CACert)\n\tif caCertPath == \"\" {\n\t\treturn tlsConfig, nil\n\t}\n\n\tcaCertPEM, errRead := os.ReadFile(caCertPath)\n\tif errRead != nil {\n\t\treturn nil, fmt.Errorf(\"home tls: read ca-cert: %w\", errRead)\n\t}\n\n\tcertPool, errPool := x509.SystemCertPool()\n\tif errPool != nil || certPool == nil {\n\t\tcertPool = x509.NewCertPool()\n\t}\n\tif !certPool.AppendCertsFromPEM(caCertPEM) {\n\t\treturn nil, fmt.Errorf(\"home tls: ca-cert contains no PEM certificates\")\n\t}\n\ttlsConfig.RootCAs = certPool\n\n\treturn tlsConfig, nil\n}\n\nfunc (c *Client) commandClient() (*redis.Client, error) {\n\tif c == nil || c.dispatchFenced.Load() {\n\t\treturn nil, ErrDispatchFenced\n\t}\n\tif errEnsure := c.ensureClients(); errEnsure != nil {\n\t\treturn nil, errEnsure\n\t}\n\tc.mu.Lock()\n\tdefer c.mu.Unlock()\n\tif c.dispatchFenced.Load() {\n\t\treturn nil, ErrDispatchFenced\n\t}","sourceCodeStart":643,"sourceCodeEnd":679,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/home/client.go#L643-L679","documentation":"Returned in internal/home/client.go when the ca-cert file was read successfully but certPool.AppendCertsFromPEM returned false — the file contains no parseable PEM certificates. The system pool fallback is irrelevant here; the configured CA file itself must contribute at least one certificate.","triggerScenarios":"ca-cert file is empty, truncated, or contains keys/other data but no CERTIFICATE blocks; PEM headers corrupted (missing dashes, embedded whitespace from copy-paste); file is in DER format.","commonSituations":"Secret mounted as an empty file (Kubernetes optional secret missing); CA fetched via a pipeline that HTML-escaped or base64-didn't-decode it; DER .cer saved where PEM expected.","solutions":["Check file content: openssl x509 -in ca.pem -noout must succeed","If empty, re-distribute the CA from the home server or fix the secret mount","If DER, convert: openssl x509 -in ca.der -inform DER -out ca.pem"],"exampleFix":"# verify\nopenssl x509 -in /etc/cliproxy/ca.pem -noout || echo \"bad PEM\"\n\n# DER -> PEM if needed\nopenssl x509 -in /etc/cliproxy/ca.cer -inform DER -out /etc/cliproxy/ca.pem","handlingStrategy":"validation","validationCode":"pemBytes, err := os.ReadFile(cfg.TLS.CACert)\nif err != nil { return err }\nif !x509.NewCertPool().AppendCertsFromPEM(pemBytes) {\n    return fmt.Errorf(\"home ca-cert %s contains no PEM certificates\", cfg.TLS.CACert)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate CA files with `openssl x509 -in ca.pem -noout` in CI","Checksum distributed CA files and compare against the enrollment record"],"tags":["go","tls","pem","certificate","home"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}