slackhq/nebula · error

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

Error message

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

What it means

Wrapping error in loadPrivateKey: the inline PEM supplied via pki.key (a literal PEM string containing -----BEGIN rather than a path) failed to unmarshal as a private key. The offending value is reported as "<inline>" with the underlying error appended via %s.

Source

Thrown at pki.go:508

	return &cs, nil
}

func loadPrivateKey(privPathOrPEM string) (rawKey []byte, curve cert.Curve, isPkcs11 bool, err error) {
	var pemPrivateKey []byte
	if strings.Contains(privPathOrPEM, "-----BEGIN") {
		pemPrivateKey = []byte(privPathOrPEM)
		privPathOrPEM = "<inline>"
		rawKey, _, curve, err = cert.UnmarshalPrivateKeyFromPEM(pemPrivateKey)
		if err != nil {
			return nil, curve, false, fmt.Errorf("error while unmarshaling pki.key %s: %s", privPathOrPEM, err)
		}
	} else if strings.HasPrefix(privPathOrPEM, "pkcs11:") {
		rawKey = []byte(privPathOrPEM)
		return rawKey, cert.Curve_P256, true, nil
	} else {
		pemPrivateKey, err = os.ReadFile(privPathOrPEM)
		if err != nil {
			return nil, curve, false, fmt.Errorf("unable to read pki.key file %s: %s", privPathOrPEM, err)
		}
		rawKey, _, curve, err = cert.UnmarshalPrivateKeyFromPEM(pemPrivateKey)
		if err != nil {
			return nil, curve, false, fmt.Errorf("error while unmarshaling pki.key %s: %s", privPathOrPEM, err)
		}
	}

	return
}

func loadCertificate(b []byte) (cert.Certificate, []byte, error) {
	c, b, err := cert.UnmarshalCertificateFromPEM(b)
	if err != nil {
		return nil, b, fmt.Errorf("error while unmarshaling pki.cert: %w", err)
	}

	if c.Expired(time.Now()) {
		return nil, b, fmt.Errorf("nebula certificate for this host is expired")

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Fix the inline PEM to be a valid Nebula private key (correct banner, untruncated base64)
  2. Point pki.key at the key file path instead of pasting the PEM
  3. If the key is encrypted, provide it in a form/config the loader supports
Defensive patterns

Strategy: validation

Validate before calling

// stat the key file and check readability before starting
func keyFileReadable(path string) error {
    fi, err := os.Stat(path)
    if err != nil { return err }
    if fi.IsDir() { return fmt.Errorf("%s is a directory", path) }
    f, err := os.Open(path); if err != nil { return err }
    return f.Close()
}

Try / catch

if err := loadPrivateKey(keyPath); err != nil {
    var pathErr *os.PathError
    if errors.As(err, errors.Unwrap(err), &pathErr) || strings.Contains(err.Error(), "unable to read pki.key") {
        log.Fatalf("cannot read pki.key at %s; check path, mount and permissions: %v", keyPath, err)
    }
    return err
}

Prevention

When it happens

Trigger: Thrown at pki.go:508 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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