slackhq/nebula · error
error while unmarshaling pki.key %s: %s
Error message
error while unmarshaling pki.key %s: %s
What it means
loadPrivateKey treats pki.key values not starting with '-----BEGIN' or 'pkcs11:' as file paths and calls os.ReadFile; the file could not be read. The %s fields carry the path and the OS error (e.g. no such file, permission denied).
Source
Thrown at pki.go:500
if network.Addr().Is4() {
addr := network.Masked().Addr().As4()
mask := net.CIDRMask(network.Bits(), network.Addr().BitLen())
binary.BigEndian.PutUint32(addr[:], binary.BigEndian.Uint32(addr[:])|^binary.BigEndian.Uint32(mask))
cs.myVpnBroadcastAddrsTable.Insert(netip.PrefixFrom(netip.AddrFrom4(addr), network.Addr().BitLen()))
}
}
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
}
View on GitHub (pinned to dd8f660c0a)
Solutions
- Fix the pki.key path or create/copy the key file there
- Fix permissions so the nebula process user can read the file (chmod 600, correct owner)
- If the key is inline PEM, ensure it starts with '-----BEGIN' so it isn't treated as a path
Example fix
// before pki: key: /etc/nebula/pki.key # file absent // after nebula-cert keygen -out-key /etc/nebula/pki.key chown nebula:nebula /etc/nebula/pki.key && chmod 600 /etc/nebula/pki.key
Defensive patterns
Strategy: validation
Validate before calling
// validate inline or file-based key before handing it to nebula
func validatePrivateKey(keyValue string) error {
if strings.Contains(keyValue, "-----BEGIN") {
_, _, _, err := cert.UnmarshalPrivateKeyFromPEM([]byte(keyValue))
return err
}
if strings.HasPrefix(keyValue, "pkcs11:") { return nil }
b, err := os.ReadFile(keyValue)
if err != nil { return err }
_, _, _, err = cert.UnmarshalPrivateKeyFromPEM(b)
return err
} Type guard
func isInlinePEMKey(v string) bool { return strings.Contains(v, "-----BEGIN") }
func isPkcs11URI(v string) bool { return strings.HasPrefix(v, "pkcs11:") } Try / catch
if err := loadPrivateKey(key); err != nil {
if strings.Contains(err.Error(), "error while unmarshaling pki.key") {
log.Fatalf("pki.key is not a valid unencrypted nebula private key PEM: %v", err)
}
return err
} Prevention
- Prefer file paths over inline PEM to avoid newline/quoting corruption
- Never use encrypted private keys; strip passphrases first
- Test key parsing in a pre-start validation step
When it happens
Trigger: loadPrivateKey (from newCertStateFromConfig): pki.key is a path and os.ReadFile fails — file missing, wrong path, unreadable permissions, or directory instead of file.
Common situations: Deployed config references a key path that wasn't mounted; systemd service lacks read permission on the key; typo in path; container secret not mounted.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- no certificate state
- no pki.key path or PEM data provided
- no pki.cert path or PEM data provided
- no pki.ca path or PEM data provided
- refusing to overwrite existing cert: %s
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/a4bd43dd05eeb159.
Report an issue: GitHub.