golang/go · error
tls: received a session ticket with empty opaque ticket labe
Error message
tls: received a session ticket with empty opaque ticket label
What it means
A TLS 1.3 client received a NewSessionTicket whose ticket field (called label internally) is empty. RFC 8446 requires the ticket to be a non-empty opaque vector; an empty value is a decode error and cannot identify a resumable session.
Source
Thrown at src/crypto/tls/handshake_client_tls13.go:859
}
if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil {
return nil
}
// See RFC 8446, Section 4.6.1.
if msg.lifetime == 0 {
return nil
}
lifetime := time.Duration(msg.lifetime) * time.Second
if lifetime > maxSessionTicketLifetime {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: received a session ticket with invalid lifetime")
}
if len(msg.label) == 0 {
c.sendAlert(alertDecodeError)
return errors.New("tls: received a session ticket with empty opaque ticket label")
}
// RFC 9001, Section 4.6.1
if c.quic != nil && msg.maxEarlyData != 0 && msg.maxEarlyData != 0xffffffff {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: invalid early data for QUIC connection")
}
cipherSuite := cipherSuiteTLS13ByID(c.cipherSuite)
if cipherSuite == nil || c.resumptionSecret == nil {
return c.sendAlert(alertInternalError)
}
psk := tls13.ExpandLabel(cipherSuite.hash.New, c.resumptionSecret, "resumption",
msg.nonce, cipherSuite.hash.Size())
session := c.sessionState()
session.secret = pskView on GitHub (pinned to b6b368adc5)
Solutions
- Report to the server operator — RFC 8446 §4.6.1 forbids empty ticket values.
- If you operate the server, verify the session ticket key/seeding logic produces non-empty ciphertext.
- Disable session tickets on the client (SessionTicketsDisabled: true or omit ClientSessionCache) to tolerate the broken peer if resumption is not required.
- File an upstream issue against the offending TLS implementation.
Example fix
// client-side workaround (only if peer cannot be fixed)
cfg := &tls.Config{
SessionTicketsDisabled: true,
} Defensive patterns
Strategy: validation
Validate before calling
// Server-side: ensure ticket bytes are non-empty before sending.
if len(ticket.Label) == 0 {
return errors.New("refusing to send empty session ticket")
} Try / catch
if err != nil && strings.Contains(err.Error(), "empty opaque ticket label") {
// disable resumption against this server or file an upstream bug
cfg.SessionTicketsDisabled = true
} Prevention
- Never issue tickets with empty ticket fields.
- Test ticket generation with empty-key guard rails.
- Disable ClientSessionCache if a peer is known-broken and resumption is optional.
When it happens
Trigger: handleNewSessionTicket checks len(msg.label) == 0 after the lifetime check; if true, it sends alertDecodeError. The peer transmitted a newSessionTicketMsgTLS13 with an empty ticket body.
Common situations: A server bug generating zero-length tickets (e.g. a ticket encryptor with an empty key, a misconfigured session cache, or a stub implementation). Also seen in fuzz tests and malformed-protocol test suites.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- tls: received a session ticket with invalid lifetime
- tls: received new session ticket from a client
- tls: server sent unrequested session ticket
- tls: server selected TLS 1.3 in a renegotiation
- tls: unexpected encrypted client hello extension in server h
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/f61286b19b2e46d7.
Report an issue: GitHub.