slackhq/nebula · error
key was not %d bytes, is invalid %s private key
Error message
key was not %d bytes, is invalid %s private key
What it means
The PEM block had a valid nebula private key banner, but the decoded key bytes are not exactly 32 bytes, which both supported curves (X25519 and P256) require. The key body was truncated, extended, or otherwise corrupted after the banner was written. The library rejects it rather than deriving a broken key.
Source
Thrown at cert/pem.go:247
func UnmarshalPrivateKeyFromPEM(b []byte) ([]byte, []byte, Curve, error) {
k, r := pem.Decode(b)
if k == nil {
return nil, r, 0, fmt.Errorf("input did not contain a valid PEM encoded block")
}
var expectedLen int
var curve Curve
switch k.Type {
case X25519PrivateKeyBanner:
expectedLen = 32
curve = Curve_CURVE25519
case P256PrivateKeyBanner:
expectedLen = 32
curve = Curve_P256
default:
return nil, r, 0, fmt.Errorf("bytes did not contain a proper private key banner")
}
if len(k.Bytes) != expectedLen {
return nil, r, 0, fmt.Errorf("key was not %d bytes, is invalid %s private key", expectedLen, curve)
}
return k.Bytes, r, curve, nil
}
func UnmarshalSigningPrivateKeyFromPEM(b []byte) ([]byte, []byte, Curve, error) {
k, r := pem.Decode(b)
if k == nil {
return nil, r, 0, fmt.Errorf("input did not contain a valid PEM encoded block")
}
var curve Curve
switch k.Type {
case EncryptedEd25519PrivateKeyBanner:
return nil, nil, Curve_CURVE25519, ErrPrivateKeyEncrypted
case EncryptedECDSAP256PrivateKeyBanner:
return nil, nil, Curve_P256, ErrPrivateKeyEncrypted
case Ed25519PrivateKeyBanner:
curve = Curve_CURVE25519
if len(k.Bytes) != ed25519.PrivateKeySize {View on GitHub (pinned to dd8f660c0a)
Solutions
- Regenerate the host private key with nebula-cert keygen and redeploy it
- Decode the PEM body and assert it is exactly 32 bytes before calling the API
- Re-transfer the key file intact (compare checksums); avoid manual copy/paste of key material
Example fix
// before
block.Bytes = key[:20] // truncated
// after
if len(key) != 32 { return errors.New("bad key") }
block.Bytes = key Defensive patterns
Strategy: validation
Validate before calling
blk, _ := pem.Decode(data)
if blk != nil && len(blk.Bytes) != 32 {
return fmt.Errorf("host private key must decode to 32 bytes, got %d; regenerate the key", len(blk.Bytes))
} Type guard
func hasValidHostKeyLength(b []byte) bool {
blk, _ := pem.Decode(b)
return blk != nil && len(blk.Bytes) == 32
} Try / catch
key, _, _, err := nebula.UnmarshalPrivateKeyFromPEM(raw)
if err != nil {
return fmt.Errorf("host private key body is the wrong size; regenerate with nebula-cert keygen: %w", err)
} Prevention
- Verify checksums when distributing key files
- Avoid copy/paste of key material through editors or chat tools
- Treat any hand-modified key file as suspect and regenerate
When it happens
Trigger: Call UnmarshalPrivateKeyFromPEM with a block whose Type is X25519PrivateKeyBanner or P256PrivateKeyBanner but whose base64 body decodes to len(k.Bytes) != 32 — e.g. a half-pasted key, a key with extra bytes appended, or raw-key-size mismatch from manual encoding.
Common situations: Copy/paste truncation in editors or chat tools, secrets managers that mangled base64, hand-crafted PEM blocks from raw key material with wrong byte length, or converting from another tool's format incorrectly.
Related errors
- key was not 64 bytes, is invalid ed25519 private key
- key was not %d bytes, is invalid %s public key
- bytes did not contain a proper private key banner
- key was not %d bytes, is invalid Ed25519 private key
- key was not 32 bytes, is invalid ECDSA P256 private key
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/29b9b71c78da0611.
Report an issue: GitHub.