golang/go · error

tls: server chose an unconfigured cipher suite

Error message

tls: server chose an unconfigured cipher suite

What it means

pickCipherSuite calls mutualCipherSuite(hs.hello.cipherSuites, hs.serverHello.cipherSuite). It walks the client's offered list and returns nil if the server-chosen ID is not present. A conformant TLS server must pick a suite the client offered; selecting anything else is a protocol violation and aborts the handshake with alertHandshakeFailure.

Source

Thrown at src/crypto/tls/handshake_client.go:634

		}
		if err := hs.readFinished(c.serverFinished[:]); err != nil {
			return err
		}
	}
	if err := hs.saveSessionTicket(); err != nil {
		return err
	}

	c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random)
	c.isHandshakeComplete.Store(true)

	return nil
}

func (hs *clientHandshakeState) pickCipherSuite() error {
	if hs.suite = mutualCipherSuite(hs.hello.cipherSuites, hs.serverHello.cipherSuite); hs.suite == nil {
		hs.c.sendAlert(alertHandshakeFailure)
		return errors.New("tls: server chose an unconfigured cipher suite")
	}

	hs.c.cipherSuite = hs.suite.id
	return nil
}

func (hs *clientHandshakeState) doFullHandshake() error {
	c := hs.c

	msg, err := c.readHandshake(&hs.finishedHash)
	if err != nil {
		return err
	}
	certMsg, ok := msg.(*certificateMsg)
	if !ok || len(certMsg.certificates) == 0 {
		c.sendAlert(alertUnexpectedMessage)
		return unexpectedMessageError(certMsg, msg)
	}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Leave Config.CipherSuites nil so Go uses its curated default suite list (includes modern AEAD TLS 1.2 and TLS 1.3 suites).
  2. If you must pin, include at least one AEAD suite the server speaks: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 / TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 / TLS 1.3 suites.
  3. Update the server's cipher configuration to offer suites the client supports.
  4. Re-evaluate whether the FIPS build is appropriate for this peer.

Example fix

// before: overly restrictive pinning
cfg := &tls.Config{CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384}}
// after: trust Go's defaults
cfg := &tls.Config{}
Defensive patterns

Strategy: validation

Validate before calling

// Validate that your pinned CipherSuites overlap with the defaults Go offers,
// and include at least one AEAD suite.
func validateCipherSuites(cs []uint16) error {
    if len(cs) == 0 { return nil }
    allowed := map[uint16]bool{
        tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: true,
        tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: true,
        tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: true,
        tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: true,
        tls.TLS_AES_128_GCM_SHA256: true,
        tls.TLS_AES_256_GCM_SHA384: true,
        tls.TLS_CHACHA20_POLY1305_SHA256: true,
    }
    for _, c := range cs {
        if !allowed[c] { return fmt.Errorf("unsupported/weak cipher suite: %x", c) }
    }
    return nil
}

Type guard

func isUnconfiguredCipherSuite(err error) bool {
    return err != nil && strings.Contains(err.Error(), "server chose an unconfigured cipher suite")
}

Try / catch

if _, err := tls.Dial("tcp", addr, cfg); err != nil {
    if isUnconfiguredCipherSuite(err) {
        // Retry once with the default suite list.
        cfg.CipherSuites = nil
        _, err = tls.Dial("tcp", addr, cfg)
    }
}

Prevention

When it happens

Trigger: Config.CipherSuites is set to a restrictive list that has no overlap with what the server selected; FIPS-only Go build (GOEXPERIMENT=fips140) strips non-approved suites; server is misconfigured or being manipulated; server picked a disabled/weak suite like TLS_RSA_WITH_3DES_EDE_CBC_SHA.

Common situations: Pinning cipher suites too narrowly; FIPS 140-3 module build connecting to a server expecting non-approved suites; old server that only offers RC4/3DES; client and server on disjoint crypto policies.

Understand the failure class

Related errors


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