golang/go · error

tls: received a session ticket with invalid lifetime

Error message

tls: received a session ticket with invalid lifetime

What it means

A TLS 1.3 client received a NewSessionTicket whose lifetime field exceeds maxSessionTicketLifetime (7 days, per RFC 8446 §4.6.1). The server is forbidden from advertising a ticket valid longer than seven days; doing so is an illegal_parameter alert condition.

Source

Thrown at src/crypto/tls/handshake_client_tls13.go:854

func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error {
	if !c.isClient {
		c.sendAlert(alertUnexpectedMessage)
		return errors.New("tls: received new session ticket from a client")
	}

	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)
	}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Report the bug to the server operator; RFC 8446 caps ticket_lifetime at 7 days.
  2. If you control the server, set ticket lifetime to <= 604800 seconds (commonly 86400 for 24h).
  3. Continue without session resumption — the client aborts this ticket but can negotiate a fresh full handshake.
  4. If interoperating with a known-broken peer, file an upstream issue rather than suppressing the alert.

Example fix

// server-side fix (Go)
cfg := &tls.Config{
    SessionTicketsDisabled: false,
    // Go enforces maxSessionTicketLifetime internally; do not try to override.
}
// If using a custom ticket store, ensure issued tickets carry lifetime <= 7*24*time.Hour.
Defensive patterns

Strategy: validation

Validate before calling

// Server-side: cap ticket lifetime at issuance to the RFC maximum.
const maxLifetime = 7 * 24 * time.Hour // 604800s
// Go enforces this; if you maintain a custom ticket store, never write a
// ticket with lifetime > maxLifetime.

Try / catch

cfg := &tls.Config{ClientSessionCache: tls.NewClientSessionCache(0)}
// On handshake error:
if err != nil && strings.Contains(err.Error(), "invalid lifetime") {
    // peer bug; report upstream, disable resumption against this host
    cfg.ClientSessionCache = nil
}

Prevention

When it happens

Trigger: handleNewSessionTicket computes lifetime = msg.lifetime seconds and compares against maxSessionTicketLifetime; if larger, it sends alertIllegalParameter. The peer server sent a ticket_lifetime greater than 604800 seconds.

Common situations: A misconfigured or non-compliant server (custom TLS stack, some older OpenSSL forks, or a testing harness) advertising oversized lifetimes. Legitimate servers cap at 7 days.

Understand the failure class

Related errors


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