slackhq/nebula · error
ErrInvalidPrivateKey
ErrInvalidPrivateKey
Error message
invalid private key
What it means
ErrInvalidPrivateKey is returned by VerifyPrivateKey when the supplied private key cannot correspond to the certificate's public key: for ed25519 the key length must equal ed25519.PrivateKeySize (checked explicitly to avoid a slice-bounds panic), and for P256/ECDH ecdh.P256().NewPrivateKey(key) fails to parse it.
Source
Thrown at cert/errors.go:18
package cert
import (
"errors"
"fmt"
)
var (
ErrBadFormat = errors.New("bad wire format")
ErrRootExpired = errors.New("root certificate is expired")
ErrExpired = errors.New("certificate is expired")
ErrNotCA = errors.New("certificate is not a CA")
ErrNotSelfSigned = errors.New("certificate is not self-signed")
ErrBlockListed = errors.New("certificate is in the block list")
ErrFingerprintMismatch = errors.New("certificate fingerprint did not match")
ErrSignatureMismatch = errors.New("certificate signature did not match")
ErrInvalidPublicKey = errors.New("invalid public key")
ErrInvalidPrivateKey = errors.New("invalid private key")
ErrPublicPrivateCurveMismatch = errors.New("public key does not match private key curve")
ErrPublicPrivateKeyMismatch = errors.New("public key and private key are not a pair")
ErrPrivateKeyEncrypted = errors.New("private key must be decrypted")
ErrCaNotFound = errors.New("could not find ca for the certificate")
ErrUnknownVersion = errors.New("certificate version unrecognized")
ErrCertPubkeyPresent = errors.New("certificate has unexpected pubkey present")
ErrCurveMismatch = errors.New("certificate curve does not match CA")
ErrInvalidPEMBlock = errors.New("input did not contain a valid PEM encoded block")
ErrInvalidPEMCertificateBanner = errors.New("bytes did not contain a proper certificate banner")
ErrInvalidPEMX25519PublicKeyBanner = errors.New("bytes did not contain a proper X25519 public key banner")
ErrInvalidPEMX25519PrivateKeyBanner = errors.New("bytes did not contain a proper X25519 private key banner")
ErrInvalidPEMEd25519PublicKeyBanner = errors.New("bytes did not contain a proper Ed25519 public key banner")
ErrInvalidPEMEd25519PrivateKeyBanner = errors.New("bytes did not contain a proper Ed25519 private key banner")
ErrNoPeerStaticKey = errors.New("no peer static key was present")
ErrNoPayload = errors.New("provided payload was empty")
View on GitHub (pinned to dd8f660c0a)
Solutions
- Ensure the key file is the full private key in the expected format and decode armor (pem.Decode) before passing the raw bytes.
- Check the key type matches the certificate's curve (ed25519 vs P256) — regenerate the key pair with nebula-cert keygen if mismatched.
- Verify key length: 64 bytes for ed25519 private keys; fix cut/paste truncation.
- Pair the certificate with the key generated together with it rather than a random existing key.
Example fix
// before
key, _ := os.ReadFile("host.pub") // wrong file
cert.VerifyPrivateKey(hostName, key) // ErrInvalidPrivateKey
// after
block, _ := pem.Decode(hostKeyPEM)
cert.VerifyPrivateKey(hostName, block.Bytes) // matching .key file Defensive patterns
Strategy: validation
Validate before calling
const ed25519PrivateKeySize = 64
if len(key) != ed25519PrivateKeySize {
return fmt.Errorf("private key must be %d bytes, got %d", ed25519PrivateKeySize, len(key))
} Type guard
func isEd25519PrivateKey(key []byte) bool {
return len(key) == ed25519.PrivateKeySize
} Try / catch
if err := c.VerifyPrivateKey(hostName, key); errors.Is(err, cert.ErrInvalidPrivateKey) {
return fmt.Errorf("key file wrong size/curve for cert; regenerate keypair with nebula-cert keygen")
} Prevention
- Pass the private key file, never the .pub file.
- pem.Decode key files before passing raw bytes.
- Match key curve to certificate curve (ed25519 vs P256); generate pairs together.
When it happens
Trigger: cert.VerifyPrivateKey on a v2 cert (cert/cert_v2.go:183,192) when the ed25519 key bytes are the wrong length, or the NIST-Curve key bytes are not a valid P256 scalar — wrong-size PEM, hex/base64 decoding issues, or a key from a different curve.
Common situations: Passing a public key file where a private key is expected; truncated or armored private key files (PEM header not stripped); key generated on a different curve than the certificate's curve; ed25519 vs P256 mismatch after regeneration.
Related errors
- ErrNotCA
- ErrInvalidPublicKey
- Empty configuration
- group should contain a single value, an array with more than
- specific port required, got 0
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/fab704c15176c325.
Report an issue: GitHub.