golang/go · critical

tls: internal error: unknown cipher suite

Error message

tls: internal error: unknown cipher suite

What it means

An internal invariant was violated: the connection's negotiated cipher suite (c.cipherSuite) was not found by cipherSuiteTLS13ByID when attempting to send a session ticket. This should never occur in a correctly functioning TLS 1.3 connection because the cipher suite was already used throughout the handshake. It indicates memory corruption, a race condition mutating connection state, or a bug in the cipher suite negotiation path.

Source

Thrown at src/crypto/tls/handshake_server_tls13.go:977

	finishedMsg := &finishedMsg{
		verifyData: hs.clientFinished,
	}
	if err := transcriptMsg(finishedMsg, hs.transcript); err != nil {
		return err
	}

	c.resumptionSecret = hs.masterSecret.ResumptionMasterSecret(hs.transcript)

	if !hs.shouldSendSessionTickets() {
		return nil
	}
	return c.sendSessionTicket(false, nil)
}

func (c *Conn) sendSessionTicket(earlyData bool, extra [][]byte) error {
	suite := cipherSuiteTLS13ByID(c.cipherSuite)
	if suite == nil {
		return errors.New("tls: internal error: unknown cipher suite")
	}
	// ticket_nonce, which must be unique per connection, is always left at
	// zero because we only ever send one ticket per connection.
	psk := tls13.ExpandLabel(suite.hash.New, c.resumptionSecret, "resumption",
		nil, suite.hash.Size())

	m := new(newSessionTicketMsgTLS13)

	state := c.sessionState()
	state.secret = psk
	state.EarlyData = earlyData
	state.Extra = extra
	if c.config.WrapSession != nil {
		var err error
		m.label, err = c.config.WrapSession(c.connectionStateLocked(), state)
		if err != nil {
			return err
		}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. This is an internal error — report it as a bug if using unmodified Go standard library.
  2. If using a forked crypto/tls, verify all TLS 1.3 cipher suite IDs are properly registered in cipherSuiteTLS13ByID.
  3. Check for data races with go test -race in the surrounding code.
  4. Ensure no unsafe code is corrupting the Conn struct.
Defensive patterns

Strategy: try-catch

Validate before calling

// This is an internal invariant violation; no pre-check can prevent it.
// Verify cipher suite is valid at config time:
func validateCipherSuites(suites []uint16) error {
    for _, id := range suites {
        if cipherSuiteTLS13ByID(id) == nil && isTLS13Suite(id) {
            return fmt.Errorf("unregistered TLS 1.3 cipher suite: %04x", id)
        }
    }
    return nil
}

Try / catch

// If this error occurs, it's a bug — capture context and report
if err := conn.Handshake(); err != nil {
    if strings.Contains(err.Error(), "internal error: unknown cipher suite") {
        // This should never happen with stock Go — report as bug
        log.Printf("BUG: unknown cipher suite %04x during session ticket", conn.cipherSuite)
    }
}

Prevention

When it happens

Trigger: Called from sendSessionTicket or sendSessionTickets after the handshake is complete. The c.cipherSuite field contains a value that cipherSuiteTLS13ByID doesn't recognize as a valid TLS 1.3 cipher suite. This is theoretically unreachable in normal operation.

Common situations: Internal Go runtime or crypto/tls bug; memory corruption from an unsafe pointer operation elsewhere; a custom fork of the TLS package that modified cipher suite registration; extremely rare race condition on connection state.

Understand the failure class

Related errors


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