golang/go · critical

tls: internal error: supportsCurve accepted unimplemented cu

Error message

tls: internal error: supportsCurve accepted unimplemented curve

What it means

An internal invariant violation: config.supportsCurve returned true for a curve ID, but curveForCurveID could not map that same curve ID to an actual elliptic curve implementation. This means supportsCurve is accepting a curve that generateECDHEKey cannot handle. This error indicates a bug in the crypto/tls package itself — supportsCurve and curveForCurveID are out of sync.

Source

Thrown at src/crypto/tls/key_agreement.go:170

	// 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))
	copy(serverECDHEParams[4:], ecdhePublic)

	priv, ok := cert.PrivateKey.(crypto.Signer)

View on GitHub (pinned to b6b368adc5)

Solutions

  1. If using a stock Go installation, report this as a Go runtime bug.
  2. If using a forked crypto/tls, verify that every curve accepted by supportsCurve has a corresponding entry in curveForCurveID.
  3. Rebuild from a clean source tree to rule out corruption.
  4. Check that the Go version is not from a broken or experimental build.
Defensive patterns

Strategy: try-catch

Validate before calling

// Internal invariant — no pre-check is possible.
// Verify you're using an unmodified Go standard library:
func checkGoTLSVersion() error {
    // This error should never occur with stock Go
    return nil
}

Try / catch

// If this fires, it's a bug in the crypto/tls package or a fork
if err := conn.Handshake(); err != nil {
    if strings.Contains(err.Error(), "supportsCurve accepted unimplemented curve") {
        log.Printf("BUG: internal curve registry inconsistency: %v", err)
        // Report to Go team if using stock Go
    }
}

Prevention

When it happens

Trigger: Theoretically unreachable in a correctly functioning standard library. Would fire if someone added a CurveID to the supported list in supportsCurve but forgot to register it in curveForCurveID, or vice versa.

Common situations: A forked or modified crypto/tls package where supportsCurve and curveForCurveID were updated inconsistently; a build from a corrupted or incomplete source tree; extremely unlikely with stock Go.

Understand the failure class

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/f37dfa5a2b2f5efa. Report an issue: GitHub.