golang/go · error

tls: server sent unrequested session ticket

Error message

tls: server sent unrequested session ticket

What it means

Thrown during the TLS 1.2-or-earlier client handshake in readSessionTicket() when the server sends a NewSessionTicket message but the client did not include the SessionTicket extension in its ClientHello. RFC 5077 requires servers to only send session tickets to clients that advertised support via the SessionTicket extension.

Source

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

	}

	if err := transcriptMsg(serverFinished, &hs.finishedHash); err != nil {
		return err
	}

	copy(out, verify)
	return nil
}

func (hs *clientHandshakeState) readSessionTicket() error {
	if !hs.serverHello.ticketSupported {
		return nil
	}
	c := hs.c

	if !hs.hello.ticketSupported {
		c.sendAlert(alertIllegalParameter)
		return errors.New("tls: server sent unrequested session ticket")
	}

	msg, err := c.readHandshake(&hs.finishedHash)
	if err != nil {
		return err
	}
	sessionTicketMsg, ok := msg.(*newSessionTicketMsg)
	if !ok {
		c.sendAlert(alertUnexpectedMessage)
		return unexpectedMessageError(sessionTicketMsg, msg)
	}

	hs.ticket = sessionTicketMsg.ticket
	return nil
}

func (hs *clientHandshakeState) saveSessionTicket() error {
	if hs.ticket == nil {

View on GitHub (pinned to b6b368adc5)

Solutions

  1. If you control the client, remove config.SessionTicketsDisabled=true or set it to false (the default) so the client advertises ticket support.
  2. If you control the server, fix it to only send NewSessionTicket when the client included the SessionTicket extension.
  3. If neither side is under your control, report the bug to the server operator — this is a server-side protocol violation.
  4. As a workaround, pin the client to TLS 1.3 which handles session resumption via NewSessionTicket messages unconditionally.

Example fix

// before
config := &tls.Config{
    SessionTicketsDisabled: true,
}
conn, err := tls.Dial("tcp", addr, config)

// after — let the client advertise session ticket support
config := &tls.Config{}
conn, err := tls.Dial("tcp", addr, config)
Defensive patterns

Strategy: try-catch

Try / catch

// Session ticket errors are untyped strings — match by substring
conn, err := tls.Dial("tcp", addr, config)
if err != nil {
    if strings.Contains(err.Error(), "server sent unrequested session ticket") {
        // Server bug: enable session tickets in config and retry,
        // or report to server operator
        config.SessionTicketsDisabled = false
        conn, err = tls.Dial("tcp", addr, config)
    }
    if err != nil {
        log.Fatalf("TLS dial failed: %v", err)
    }
}

Prevention

When it happens

Trigger: Triggered when hs.serverHello.ticketSupported is true (server supports tickets) AND hs.hello.ticketSupported is false (client omitted the SessionTicket extension). The client sends alertIllegalParameter and aborts the handshake.

Common situations: Connecting to a non-compliant TLS server that unconditionally sends NewSessionTicket regardless of client preference. Custom tls.Config with SessionTicketsDisabled=true but the server ignores the absence of the extension. Buggy or older server implementations that don't check the client's ticket support.

Understand the failure class

Related errors


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