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

  1. Set `curve` in the config to a supported value: "25519" or "P256".
  2. Check for typos/case — the match is on exact strings like "P256", not "p256" or "secp256k1".
  3. If P-384 or another curve is needed, that is not supported; stay with the supported curves.
  4. 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

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


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/5a04071ed55dc47a. Report an issue: GitHub.