{"record":{"id":"5c1ab5cf225258d4","repo":"golang/go","slug":"tls-server-resumed-a-session-with-a-different-ver","errorCode":null,"errorMessage":"tls: server resumed a session with a different version","messagePattern":"tls: server resumed a session with a different version","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/tls/handshake_client.go","lineNumber":938,"sourceCode":"\t\t\treturn false, errors.New(\"tls: incorrect renegotiation extension contents\")\n\t\t}\n\t}\n\n\tif err := checkALPN(hs.hello.alpnProtocols, hs.serverHello.alpnProtocol, false); err != nil {\n\t\tc.sendAlert(alertUnsupportedExtension)\n\t\treturn false, err\n\t}\n\tc.clientProtocol = hs.serverHello.alpnProtocol\n\n\tc.scts = hs.serverHello.scts\n\n\tif !hs.serverResumedSession() {\n\t\treturn false, nil\n\t}\n\n\tif hs.session.version != c.vers {\n\t\tc.sendAlert(alertHandshakeFailure)\n\t\treturn false, errors.New(\"tls: server resumed a session with a different version\")\n\t}\n\n\tif hs.session.cipherSuite != hs.suite.id {\n\t\tc.sendAlert(alertHandshakeFailure)\n\t\treturn false, errors.New(\"tls: server resumed a session with a different cipher suite\")\n\t}\n\n\t// RFC 7627, Section 5.3\n\tif hs.session.extMasterSecret != hs.serverHello.extendedMasterSecret {\n\t\tc.sendAlert(alertHandshakeFailure)\n\t\treturn false, errors.New(\"tls: server resumed a session with a different EMS extension\")\n\t}\n\n\t// Restore master secret and certificates from previous state\n\ths.masterSecret = hs.session.secret\n\tc.extMasterSecret = hs.session.extMasterSecret\n\tc.peerCertificates = hs.session.peerCertificates\n\tc.verifiedChains = hs.session.verifiedChains","sourceCodeStart":920,"sourceCodeEnd":956,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/tls/handshake_client.go#L920-L956","documentation":"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.","triggerScenarios":"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.","commonSituations":"Misconfigured server ticket cache spanning versions; rare in mainstream servers.","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."],"exampleFix":"// Disable resumption when the server mishandles session versions\ncfg := &tls.Config{SessionTicketsDisabled: true}","handlingStrategy":"fallback","validationCode":null,"typeGuard":"func isResumptionVersionMismatch(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"server resumed a session with a different version\")\n}","tryCatchPattern":"if _, err := tls.Dial(\"tcp\", addr, cfg); err != nil {\n    if isResumptionVersionMismatch(err) {\n        // Retry with session resumption disabled; server ticket cache is inconsistent.\n        cfg.SessionTicketsDisabled = true\n        cfg.ClientSessionCache = nil\n        _, err = tls.Dial(\"tcp\", addr, cfg)\n    }\n}","preventionTips":["Rotate server session ticket keys to clear stale state.","Disable client session resumption if the server is non-conformant."],"tags":["tls","session","resumption","protocol"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}