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
- This is an internal error — report it as a bug if using unmodified Go standard library.
- If using a forked crypto/tls, verify all TLS 1.3 cipher suite IDs are properly registered in cipherSuiteTLS13ByID.
- Check for data races with go test -race in the surrounding code.
- 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
- Don't fork crypto/tls without keeping cipher suite registration consistent.
- Report this immediately if using unmodified Go — it indicates a runtime bug.
- Run go test -race to catch data races affecting connection state.
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
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- tls: client sent encrypted_client_hello extension with unsup
- tls: client sent encrypted_client_hello extension but did no
- tls: server changed cipher suite after a HelloRetryRequest
- tls: server chose an unconfigured cipher suite
- tls: internal error: supportsCurve accepted unimplemented cu
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/a4285151ff872a86.
Report an issue: GitHub.