{"record":{"id":"3747dc84e170ef88","repo":"slackhq/nebula","slug":"unable-to-read-pki-ca-file-s-s","errorCode":null,"errorMessage":"unable to read pki.ca file %s: %s","messagePattern":"unable to read pki\\.ca file (.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pki.go","lineNumber":554,"sourceCode":"\n\treturn c, b, nil\n}\n\nfunc loadCAPoolFromConfig(l *slog.Logger, c *config.C) (*cert.CAPool, error) {\n\tcaPathOrPEM := c.GetString(\"pki.ca\", \"\")\n\tif caPathOrPEM == \"\" {\n\t\treturn nil, errors.New(\"no pki.ca path or PEM data provided\")\n\t}\n\n\tvar caReader io.ReadCloser\n\tvar err error\n\n\tif strings.Contains(caPathOrPEM, \"-----BEGIN\") {\n\t\tcaReader = io.NopCloser(strings.NewReader(caPathOrPEM))\n\t} else {\n\t\tcaReader, err = os.Open(caPathOrPEM)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unable to read pki.ca file %s: %s\", caPathOrPEM, err)\n\t\t}\n\t}\n\tdefer caReader.Close()\n\n\tcaPool, err := cert.NewCAPoolFromPEMReader(caReader)\n\tif errors.Is(err, cert.ErrExpired) {\n\t\tvar expired int\n\t\tfor _, crt := range caPool.CAs {\n\t\t\tif crt.Certificate.Expired(time.Now()) {\n\t\t\t\texpired++\n\t\t\t\tl.Warn(\"expired certificate present in CA pool\", \"cert\", crt)\n\t\t\t}\n\t\t}\n\n\t\tif expired >= len(caPool.CAs) {\n\t\t\treturn nil, errors.New(\"no valid CA certificates present\")\n\t\t}\n","sourceCodeStart":536,"sourceCodeEnd":572,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/pki.go#L536-L572","documentation":"loadCAPoolFromConfig reads pki.ca either as inline PEM or from a file via os.Open; when the file cannot be opened it wraps the OS error with this message. The trusted-CA pool is mandatory, so startup/reload aborts without it.","triggerScenarios":"reloadCAPool (via newCertStateFromConfig or config reload) with pki.ca set to a path that does not exist, has wrong permissions, or points at a directory instead of a file.","commonSituations":"Typo in the pki.ca path; file deployed with root-only permissions and nebula runs unprivileged; path relative to the wrong working directory when running as a service; file deleted by config management.","solutions":["Fix the pki.ca path in config to the actual ca.crt location","Correct file permissions so the nebula process user can read it (chmod/chown)","Or inline the CA PEM directly as the pki.ca value instead of a path","Verify with 'sudo -u <nebula-user> cat /path/to/ca.crt'"],"exampleFix":"// before\npki:\n  ca: /etc/nebula/car.crt    # typo\n// after\npki:\n  ca: /etc/nebula/ca.crt","handlingStrategy":"validation","validationCode":"if fi, err := os.Stat(cfg.PKI.CA); err != nil || fi.IsDir() {\n    return fmt.Errorf(\"pki.ca not readable: %v\", err)\n}","typeGuard":"func caFileReadable(path string) bool {\n    f, err := os.Open(path)\n    if err != nil { return false }\n    f.Close()\n    return true\n}","tryCatchPattern":"pool, err := loadCAPoolFromConfig(logger, cfg)\nif err != nil && strings.HasPrefix(err.Error(), \"unable to read pki.ca\") {\n    return fmt.Errorf(\"check pki.ca path/permissions: %w\", err)\n}","preventionTips":["Use absolute paths for pki.ca in service units","Ensure the nebula service user can read cert files (chown/chmod)","Deploy CA file alongside certs via config management with existence checks","Or embed the CA PEM inline in config to avoid path issues"],"tags":["pki","ca","file-io","config"],"backgroundTag":"file-not-found","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}