golang/go · error

tls: server selected unsupported group

Error message

tls: server selected unsupported group

What it means

Thrown during HelloRetryRequest processing when the server's selected_group in key_share is a group the client did not advertise in its supported_groups (supportedCurves) list. The server requested a key share for an unsupported group.

Source

Thrown at src/crypto/tls/handshake_client_tls13.go:315

		return errors.New("tls: server sent an unnecessary HelloRetryRequest message")
	}

	if hs.serverHello.cookie != nil {
		hello.cookie = hs.serverHello.cookie
	}

	if hs.serverHello.serverShare.group != 0 {
		c.sendAlert(alertDecodeError)
		return errors.New("tls: received malformed key_share extension")
	}

	// If the server sent a key_share extension selecting a group, ensure it's
	// a group we advertised but did not send a key share for, and send a key
	// share for it this time.
	if curveID := hs.serverHello.selectedGroup; curveID != 0 {
		if !slices.Contains(hello.supportedCurves, curveID) {
			c.sendAlert(alertIllegalParameter)
			return errors.New("tls: server selected unsupported group")
		}
		if slices.ContainsFunc(hs.hello.keyShares, func(ks keyShare) bool {
			return ks.group == curveID
		}) {
			c.sendAlert(alertIllegalParameter)
			return errors.New("tls: server sent an unnecessary HelloRetryRequest key_share")
		}
		ke, err := keyExchangeForCurveID(curveID)
		if err != nil {
			c.sendAlert(alertInternalError)
			return errors.New("tls: internal error: supportsCurve accepted unimplemented curve")
		}
		hs.keyShareKeys, hello.keyShares, err = ke.keyShares(c.config.rand())
		if err != nil {
			c.sendAlert(alertInternalError)
			return err
		}
		// Do not send the fallback ECDH key share in a HRR response.

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Check tls.Config.CurvePreferences — if set, ensure it includes common groups: tls.X25519, tls.CurveP256, tls.CurveP384.
  2. Leave CurvePreferences nil to use Go's defaults (recommended): X25519, P-256, P-384.
  3. Verify the server's preferred groups and ensure client supports at least one.
  4. Update Go to a recent version for the latest curve support.

Example fix

// before — only X25519 advertised, server wants P-256
config := &tls.Config{
    CurvePreferences: []tls.CurveID{tls.X25519},
}

// after — use defaults or include multiple curves
config := &tls.Config{
    // CurvePreferences nil = Go defaults (X25519, P-256, P-384)
}
// or explicitly:
// CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256, tls.CurveP384}
Defensive patterns

Strategy: validation

Validate before calling

// Validate curve preferences before connecting
func validateCurvePreferences(config *tls.Config) error {
    if config.CurvePreferences == nil {
        return nil // nil = Go defaults, always OK
    }
    commonCurves := map[tls.CurveID]bool{
        tls.X25519:    true,
        tls.CurveP256: true,
        tls.CurveP384: true,
    }
    for _, c := range config.CurvePreferences {
        if commonCurves[c] {
            return nil // at least one common curve
        }
    }
    return fmt.Errorf("CurvePreferences excludes all common curves (X25519, P-256, P-384)")
}

Try / catch

conn, err := tls.Dial("tcp", addr, config)
if err != nil {
    if strings.Contains(err.Error(), "server selected unsupported group") {
        // Reset to defaults and retry
        config.CurvePreferences = nil
        conn, err = tls.Dial("tcp", addr, config)
    }
}

Prevention

When it happens

Trigger: Triggered when slices.Contains(hello.supportedCurves, curveID) returns false for the server-selected curveID. The client sends alertIllegalParameter. The server asked for a key share on a curve the client doesn't support or didn't advertise.

Common situations: Client tls.Config.CurvePreferences is explicitly restricted to a subset that excludes the server's preferred group (e.g. only X25519 but server wants P-384). Client and server group configuration mismatch. Server bug selecting an unadvertised group. Older Go version lacking support for newer groups.

Understand the failure class

Related errors


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