slackhq/nebula · error
unsupported curve: %s
Error message
unsupported curve: %s
What it means
newCipherSuite maps a configured curve name (plus cipher and pkcs11backed flag) to Noise DH functions. If the curve string is not one of the supported values (e.g. 25519 or P256), it returns this error naming the unsupported curve.
Source
Thrown at pki.go:260
// When fips140Enforced is true (FIPS 140-only mode), non-approved algorithms
// (Curve25519 and ChaChaPoly) are rejected with an error. Callers pass
// fips140.Enforced() for fips140Enforced.
func newCipherSuite(curve cert.Curve, pkcs11backed bool, cipher string, fips140Enforced bool) (noise.CipherSuite, error) {
var dhFunc noise.DHFunc
switch curve {
case cert.Curve_CURVE25519:
if fips140Enforced {
return nil, errors.New("pki: use of Curve25519 is not allowed in FIPS 140-only mode")
}
dhFunc = noise.DH25519
case cert.Curve_P256:
if pkcs11backed {
dhFunc = noiseutil.DHP256PKCS11
} else {
dhFunc = noiseutil.DHP256
}
default:
return nil, fmt.Errorf("unsupported curve: %s", curve)
}
if cipher == "chachapoly" {
if fips140Enforced {
return nil, errors.New("pki: use of ChaChaPoly is not allowed in FIPS 140-only mode")
}
return noise.NewCipherSuite(dhFunc, noise.CipherChaChaPoly, noise.HashSHA256), nil
}
return noise.NewCipherSuite(dhFunc, noiseutil.CipherAESGCM, noise.HashSHA256), nil
}
func (cs *CertState) String() string {
b, err := cs.MarshalJSON()
if err != nil {
return fmt.Sprintf("error marshaling certificate state: %v", err)
}
return string(b)
}View on GitHub (pinned to dd8f660c0a)
Solutions
- Set `curve` in the config to a supported value: "25519" or "P256".
- Check for typos/case — the match is on exact strings like "P256", not "p256" or "secp256k1".
- If P-384 or another curve is needed, that is not supported; stay with the supported curves.
- If the cert is P-256 but config says 25519 (or vice versa), align `curve` with the certificate's curve.
Example fix
# before pki: curve: secp256r1 # after pki: curve: P256
Defensive patterns
Strategy: validation
Validate before calling
var validCurves = map[string]bool{"25519": true, "P256": true}
func validateCurve(curve string) error {
if !validCurves[curve] {
return fmt.Errorf("curve %q not supported; use 25519 or P256", curve)
}
return nil
}
// call before loading full config
if err := validateCurve(cfg.PKI.Curve); err != nil { log.Fatal(err) } Type guard
func curveSupported(c string) bool { return c == "25519" || c == "P256" } Try / catch
cs, err := newCipherSuite(curve, cipher, fipsEnforced, pkcs11backed)
if err != nil {
if strings.Contains(err.Error(), "unsupported curve") {
return fmt.Errorf("config pki.curve must be 25519 or P256 (got %s): %w", curve, err)
}
return err
} Prevention
- Validate the whole config with `nebula -configtest` (or equivalent) before launch.
- Use only documented curve strings: 25519 or P256, exact case.
- Keep `curve` consistent with the certificate's actual curve.
- Lint config templates so external naming conventions (secp256r1 etc.) never leak in.
When it happens
Trigger: Configuring nebula with a `curve` value in the config file (or calling newCipherSuite directly, e.g. in TestNewCipherSuiteUnsupportedCurve) with a name outside the supported set such as "secp256r1", "p384", or a typo like "p25519".
Common situations: Copy-pasted config from another VPN tool using different curve naming; manual edits introducing typos; attempts to use P-384/other curves which this library doesn't implement; leftover config from older nebula versions with different accepted values.
Related errors
- Empty configuration
- group should contain a single value, an array with more than
- stats.host can not be empty
- stats.listen should not be empty
- stats.path should not be empty
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/5a04071ed55dc47a.
Report an issue: GitHub.