golang/go · error
tls: no supported elliptic curves offered
Error message
tls: no supported elliptic curves offered
What it means
During TLS 1.0–1.2 ECDHE key exchange, the server iterates the client's supportedCurves list looking for one that the server also supports (via config.supportsCurve). If no overlap is found (ka.curveID remains 0), the server cannot proceed with ECDHE key exchange. The client must offer at least one curve the server supports.
Source
Thrown at src/crypto/tls/key_agreement.go:167
preMasterSecret []byte
// curveID, signatureAlgorithm, and key are set by processServerKeyExchange
// and generateServerKeyExchange.
curveID CurveID
signatureAlgorithm SignatureScheme
key *ecdh.PrivateKey
}
func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
for _, c := range clientHello.supportedCurves {
if config.supportsCurve(ka.version, c) {
ka.curveID = c
break
}
}
if ka.curveID == 0 {
return nil, errors.New("tls: no supported elliptic curves offered")
}
if _, ok := curveForCurveID(ka.curveID); !ok {
return nil, errors.New("tls: internal error: supportsCurve accepted unimplemented curve")
}
key, err := generateECDHEKey(config.rand(), ka.curveID)
if err != nil {
return nil, err
}
ka.key = key
// See RFC 4492, Section 5.4.
ecdhePublic := key.PublicKey().Bytes()
serverECDHEParams := make([]byte, 1+2+1+len(ecdhePublic))
serverECDHEParams[0] = 3 // named curve
serverECDHEParams[1] = byte(ka.curveID >> 8)
serverECDHEParams[2] = byte(ka.curveID)
serverECDHEParams[3] = byte(len(ecdhePublic))View on GitHub (pinned to b6b368adc5)
Solutions
- Ensure the client offers at least one standard curve the server supports (X25519, P-256, P-384 are universally recommended).
- On the server, verify tls.Config.CurvePreferences includes common curves (or leave it nil for defaults).
- Update the client TLS library to one that advertises standard curves.
- If running in FIPS mode, ensure the client offers NIST curves (P-256, P-384) since X25519 may not be available.
- Prefer TLS 1.3 which has better curve negotiation and defaults.
Example fix
// before: client offers no supported curves (or server restricts too much)
cfg := &tls.Config{
CurvePreferences: []tls.CurveID{}, // empty - too restrictive
}
// after: include standard curves
cfg := &tls.Config{
CurvePreferences: []tls.CurveID{
tls.X25519, tls.CurveP256, tls.CurveP384,
},
} Defensive patterns
Strategy: validation
Validate before calling
// Server-side: verify curve configuration before accepting connections
func validateCurveConfig(cfg *tls.Config) error {
if len(cfg.CurvePreferences) == 0 {
return nil // defaults are fine
}
standardCurves := map[tls.CurveID]bool{
tls.X25519: true, tls.CurveP256: true, tls.CurveP384: true, tls.CurveP521: true,
}
for _, c := range cfg.CurvePreferences {
if !standardCurves[c] {
return fmt.Errorf("non-standard curve %v in preferences", c)
}
}
return nil
} Try / catch
// Server-side: log and close
if err := conn.Handshake(); err != nil {
if strings.Contains(err.Error(), "no supported elliptic curves") {
log.Printf("client offered no supported curves: %v", err)
}
conn.Close()
} Prevention
- Include standard curves (X25519, P-256, P-384) in CurvePreferences.
- Don't empty or over-restrict CurvePreferences.
- Monitor this error to detect clients with outdated curve support.
- For FIPS environments, ensure clients offer NIST curves.
When it happens
Trigger: Server calls ecdheKeyAgreement.generateServerKeyExchange. The clientHello.supportedCurves list is empty, or contains only curves the server doesn't support (e.g. client offers only custom/obsolete curves the server's config rejects).
Common situations: Client offers only non-standard or deprecated curves; server's CurvePreferences list is too restrictive; client configured with an empty or exotic supported curves list; version mismatch where a client only supports curves the server dropped; FIPS-mode server that restricts curve selection.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- tls: internal error: supportsCurve accepted unimplemented cu
- tls: certificate cannot be used with the selected cipher sui
- tls: server selected unsupported curve
- tls: invalid ClientKeyExchange message
- tls: certificate private key does not implement crypto.Decry
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/9b6b50ccdc85b01a.
Report an issue: GitHub.