golang/go · warning
client doesn't support certificate curve
Error message
client doesn't support certificate curve
What it means
Thrown by SupportsCertificate when the certificate is an ECDSA key on a curve (P-256/P-384/P-521) that does not appear in the client's SupportedCurves (or the server does not support that curve for the negotiated version). Without a shared curve the ECDSA cipher suite cannot be selected, so the cert is unusable for this client.
Source
Thrown at src/crypto/tls/common.go:1499
switch pub.Curve {
case elliptic.P256():
curve = CurveP256
case elliptic.P384():
curve = CurveP384
case elliptic.P521():
curve = CurveP521
default:
return supportsRSAFallback(unsupportedCertificateError(c))
}
var curveOk bool
for _, c := range chi.SupportedCurves {
if c == curve && config.supportsCurve(vers, c) {
curveOk = true
break
}
}
if !curveOk {
return errors.New("client doesn't support certificate curve")
}
ecdsaCipherSuite = true
case ed25519.PublicKey:
if vers < VersionTLS12 || len(chi.SignatureSchemes) == 0 {
return errors.New("connection doesn't support Ed25519")
}
ecdsaCipherSuite = true
case *mldsa.PublicKey:
// ML-DSA requires TLS 1.3, which we already excluded above.
return errors.New("connection doesn't support ML-DSA")
case *rsa.PublicKey:
default:
return supportsRSAFallback(unsupportedCertificateError(c))
}
} else {
return supportsRSAFallback(unsupportedCertificateError(c))
}
View on GitHub (pinned to b6b368adc5)
Solutions
- Generate or select an ECDSA cert on a curve the client advertises (P-256 is most widely supported).
- Set Config.CurvePreferences to include the cert's curve and ensure the client offers it.
- Provide multiple ECDSA certs on different curves and pick via GetCertificate using chi.SupportedCurves.
- Fall back to an RSA or Ed25519 cert when no ECDSA curve overlaps.
Example fix
// before: cert on P-521, client offers only P-256
cfg.Certificates = []tls.Certificate{p521Cert}
// after: add a P-256 cert and select by client curves
cfg.Certificates = []tls.Certificate{p256Cert, p521Cert}
cfg.GetCertificate = func(chi *tls.ClientHelloInfo) (*tls.Certificate, error) {
for _, c := range chi.SupportedCurves {
if c == tls.CurveP521 { return &p521Cert, nil }
}
return &p256Cert, nil
} Defensive patterns
Strategy: fallback
Validate before calling
// Pick an ECDSA cert whose curve the client advertises.
func pickECDSACert(chi *tls.ClientHelloInfo, byCurve map[tls.CurveID]*tls.Certificate) (*tls.Certificate, error) {
for _, c := range chi.SupportedCurves {
if cert, ok := byCurve[c]; ok { return cert, nil }
}
return nil, errors.New("client shares no ECDSA curve")
} Prevention
- Issue ECDSA certs on P-256 for maximum client compatibility.
- Provide multiple ECDSA certs on different curves and select via GetCertificate.
- Keep an RSA or Ed25519 cert as fallback when no ECDSA curve overlaps.
- Inspect chi.SupportedCurves during testing to choose the right cert inventory.
When it happens
Trigger: Server has an ECDSA cert (e.g., P-384) but the client's SupportedCurves omits that curve, or config.supportsCurve returns false for it. Reached in the ECDSA branch of SupportsCertificate after curveOk stays false.
Common situations: Cert generated on P-384/P-521 but client only offers P-256/X25519; client stripped uncommon curves for policy; multi-cert setup picking the wrong cert for the client; curve disabled by CurvePreferences.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- ECDSA verification failure
- ecdsa: private key scalar is zero or negative
- negative coordinate
- overflowing coordinate
- ecdsa: public key point is the infinity
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/0139969f6d5e8ec7.
Report an issue: GitHub.