slackhq/nebula · error
invalid curve: %v
Error message
invalid curve: %v
What it means
EncryptAndMarshalSigningPrivateKey only supports Curve_CURVE25519 (Ed25519) and Curve_P256 (ECDSA P-256). Passing any other Curve enum value (e.g. Curve_CURVE448 or an unset/unknown value) has no PEM banner mapping, so the function fails before encoding.
Source
Thrown at cert/crypto.go:189
Memory: kdfParams.Memory,
Parallelism: uint32(kdfParams.Parallelism),
Iterations: kdfParams.Iterations,
Salt: kdfParams.salt,
},
},
Ciphertext: ciphertext,
})
if err != nil {
return nil, err
}
switch curve {
case Curve_CURVE25519:
return pem.EncodeToMemory(&pem.Block{Type: EncryptedEd25519PrivateKeyBanner, Bytes: b}), nil
case Curve_P256:
return pem.EncodeToMemory(&pem.Block{Type: EncryptedECDSAP256PrivateKeyBanner, Bytes: b}), nil
default:
return nil, fmt.Errorf("invalid curve: %v", curve)
}
}
// UnmarshalNebulaEncryptedData will unmarshal a protobuf byte representation of a nebula cert into its
// protobuf-generated struct.
func UnmarshalNebulaEncryptedData(b []byte) (*NebulaEncryptedData, error) {
if len(b) == 0 {
return nil, fmt.Errorf("nil byte array")
}
var rned RawNebulaEncryptedData
err := proto.Unmarshal(b, &rned)
if err != nil {
return nil, err
}
if rned.EncryptionMetadata == nil {
return nil, fmt.Errorf("encoded EncryptionMetadata was nil")
}View on GitHub (pinned to dd8f660c0a)
Solutions
- Pass only Curve_CURVE25519 for Ed25519 keys or Curve_P256 for ECDSA P-256 keys; verify which key type you actually hold before calling
- Check that the curve value was not lost/zeroed during protobuf unmarshalling - an unset proto3 enum field reads as 0 and will fail
- If you need another curve, it is unsupported by this API; re-generate the key as Ed25519 or P-256
Example fix
// before pem, err := cert.EncryptAndMarshalSigningPrivateKey(key, pass, cert.Curve_CURVE448) // after pem, err := cert.EncryptAndMarshalSigningPrivateKey(key, pass, cert.Curve_CURVE25519)
Defensive patterns
Strategy: validation
Validate before calling
if curve != cert.Curve_CURVE25519 && curve != cert.Curve_P256 { return fmt.Errorf("unsupported curve: %v", curve) } Type guard
func isSupportedCurve(c cert.Curve) bool { return c == cert.Curve_CURVE25519 || c == cert.Curve_P256 } Try / catch
pemBytes, err := cert.EncryptAndMarshalSigningPrivateKey(key, pass, curve)
if err != nil {
if strings.Contains(err.Error(), "invalid curve") { /* check curve value source */ }
return err
} Prevention
- Only pass Curve_CURVE25519 or Curve_P256; remember proto3 enums default to 0 when unset
- Verify the curve enum survived protobuf round-trips
- Match the curve to the actual key type (Ed25519 vs ECDSA P-256)
When it happens
Trigger: Calling EncryptAndMarshalSigningPrivateKey with a signing key and a curve argument other than Curve_CURVE25519 or Curve_P256 - typically Curve(0) from an unset field or a value deserialized from an untrusted/unknown source.
Common situations: Protobuf-decoding a cert whose curve field is 0/unknown and passing it straight into encryption; copying code from a P-256 example while holding a Curve25519 key (or vice versa); adding a new curve to the enum without updating this switch.
Related errors
- invalid curve: %s
- use of Curve25519 is not allowed in FIPS 140-only mode
- use of Curve25519 is not allowed in FIPS 140-only mode
- use of Curve25519 is not allowed in FIPS 140-only mode
- ErrAlreadySeen
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/65ef5c57a6609a76.
Report an issue: GitHub.