golang/go · error
tls: server resumed a session with a different version
Error message
tls: server resumed a session with a different version
What it means
When processServerHello detects resumption (hs.serverResumedSession() returned true), the resumed session's recorded version must equal c.vers from this handshake. If hs.session.version != c.vers the server resumed a session across an incompatible version, which TLS forbids and aborts with alertHandshakeFailure.
Source
Thrown at src/crypto/tls/handshake_client.go:938
return false, errors.New("tls: incorrect renegotiation extension contents")
}
}
if err := checkALPN(hs.hello.alpnProtocols, hs.serverHello.alpnProtocol, false); err != nil {
c.sendAlert(alertUnsupportedExtension)
return false, err
}
c.clientProtocol = hs.serverHello.alpnProtocol
c.scts = hs.serverHello.scts
if !hs.serverResumedSession() {
return false, nil
}
if hs.session.version != c.vers {
c.sendAlert(alertHandshakeFailure)
return false, errors.New("tls: server resumed a session with a different version")
}
if hs.session.cipherSuite != hs.suite.id {
c.sendAlert(alertHandshakeFailure)
return false, errors.New("tls: server resumed a session with a different cipher suite")
}
// RFC 7627, Section 5.3
if hs.session.extMasterSecret != hs.serverHello.extendedMasterSecret {
c.sendAlert(alertHandshakeFailure)
return false, errors.New("tls: server resumed a session with a different EMS extension")
}
// Restore master secret and certificates from previous state
hs.masterSecret = hs.session.secret
c.extMasterSecret = hs.session.extMasterSecret
c.peerCertificates = hs.session.peerCertificates
c.verifiedChains = hs.session.verifiedChainsView on GitHub (pinned to b6b368adc5)
Solutions
- Clear/rotate the server's session ticket key so stale tickets are not resumed across versions.
- Update the server TLS stack to a version that correctly binds session version.
- Set Config.SessionTicketsDisabled = true on the client to bypass resumption if the server is unfixable.
Example fix
// Disable resumption when the server mishandles session versions
cfg := &tls.Config{SessionTicketsDisabled: true} Defensive patterns
Strategy: fallback
Type guard
func isResumptionVersionMismatch(err error) bool {
return err != nil && strings.Contains(err.Error(), "server resumed a session with a different version")
} Try / catch
if _, err := tls.Dial("tcp", addr, cfg); err != nil {
if isResumptionVersionMismatch(err) {
// Retry with session resumption disabled; server ticket cache is inconsistent.
cfg.SessionTicketsDisabled = true
cfg.ClientSessionCache = nil
_, err = tls.Dial("tcp", addr, cfg)
}
} Prevention
- Rotate server session ticket keys to clear stale state.
- Disable client session resumption if the server is non-conformant.
When it happens
Trigger: Server session cache returning a ticket/session keyed for TLS 1.3 while negotiating TLS 1.2 (or vice versa); server bug in ticket handling; downgrade attack between the original and resumed handshake.
Common situations: Misconfigured server ticket cache spanning versions; rare in mainstream servers.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- tls: server resumed a session with a different cipher suite
- tls: server resumed a session with a different EMS extension
- tls: server echoed TLS 1.3 compatibility session ID in TLS 1
- tls: received unexpected CertificateStatus message
- tls: server selected unsupported compression format
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/5c1ab5cf225258d4.
Report an issue: GitHub.