slackhq/nebula · error

unable to read pki.cert file %s: %s

Error message

unable to read pki.cert file %s: %s

What it means

newCertStateFromConfig loads the certificate chain either from an inline PEM string or by reading the pki.cert file from disk. When the path is a file (not inline PEM) and os.ReadFile fails, this error reports the path and the OS error.

Source

Thrown at pki.go:328

	if err != nil {
		return nil, err
	}

	var rawCert []byte

	pubPathOrPEM := c.GetString("pki.cert", "")
	if pubPathOrPEM == "" {
		return nil, errors.New("no pki.cert path or PEM data provided")
	}

	if strings.Contains(pubPathOrPEM, "-----BEGIN") {
		rawCert = []byte(pubPathOrPEM)
		pubPathOrPEM = "<inline>"

	} else {
		rawCert, err = os.ReadFile(pubPathOrPEM)
		if err != nil {
			return nil, fmt.Errorf("unable to read pki.cert file %s: %s", pubPathOrPEM, err)
		}
	}

	var crt, v1, v2 cert.Certificate
	for {
		// Load the certificate
		crt, rawCert, err = loadCertificate(rawCert)
		if err != nil {
			return nil, err
		}

		if fips140.Enforced() && crt.Curve() != cert.Curve_P256 {
			return nil, fmt.Errorf("pki: use of %s is not allowed in FIPS 140-only mode", crt.Curve())
		}

		switch crt.Version() {
		case cert.Version1:
			if v1 != nil {

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Fix the pki.cert path in config (use an absolute path) and confirm the file exists.
  2. Check file permissions so the nebula process user can read it.
  3. Verify the inline-PEM vs path distinction: an inline PEM string bypasses the file read entirely.
  4. If path is relative, either make it absolute or start nebula from the intended working directory.

Example fix

# before
pki:
  cert: ./pki.cert
# after
pki:
  cert: /etc/nebula/pki.cert
Defensive patterns

Strategy: validation

Validate before calling

func checkCertReadable(path string) error {
  if path == "" { return errors.New("pki.cert path empty") }
  fi, err := os.Stat(path)
  if err != nil { return fmt.Errorf("pki.cert %s: %w", path, err) }
  if fi.IsDir() { return fmt.Errorf("pki.cert %s is a directory", path) }
  f, err := os.Open(path); if err != nil { return fmt.Errorf("pki.cert %s unreadable: %w", path, err) }
  f.Close(); return nil
}
// run before starting nebula

Try / catch

cs, err := newCertStateFromConfig(...)
if err != nil {
  var pathErr *os.PathError
  if strings.Contains(err.Error(), "unable to read pki.cert file") && errors.As(err, &pathErr) {
    return fmt.Errorf("fix pki.cert path/permissions: %w", err)
  }
  return err
}

Prevention

When it happens

Trigger: reloadCerts -> newCertStateFromConfig with a pki.cert path that doesn't exist, lacks read permission, is a directory, or otherwise fails os.ReadFile.

Common situations: Nebula started from a different working directory with a relative path; cert file deleted or renamed; wrong user/permissions (e.g. running as non-root without access to /etc/nebula); typo in the `cert:` path in config; systemd unit with a different WorkingDirectory.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/8b9e16188c3a0279. Report an issue: GitHub.