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
- If you control the client, remove config.SessionTicketsDisabled=true or set it to false (the default) so the client advertises ticket support.
- If you control the server, fix it to only send NewSessionTicket when the client included the SessionTicket extension.
- If neither side is under your control, report the bug to the server operator — this is a server-side protocol violation.
- 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
- Leave SessionTicketsDisabled at its default (false) unless you have a specific reason to disable it.
- Test against the target server with openssl s_client before deploying custom tls.Config.
- For TLS 1.3, session tickets are always sent post-handshake regardless of this setting.
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
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- tls: server sent two HelloRetryRequest messages
- tls: server sent a cookie in a normal ServerHello
- tls: malformed key_share extension
- tls: server did not send a key share
- tls: server selected an invalid PSK
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/2b608aa6b3ad6a23.
Report an issue: GitHub.