golang/go · error
tls: initial handshake had non-empty renegotiation extension
Error message
tls: initial handshake had non-empty renegotiation extension
What it means
Per RFC 5746, on the very first handshake (c.handshakes == 0) when the server signals secure_renegotiation support, the renegotiation_info extension contents must be empty. If hs.serverHello.secureRenegotiation is non-empty on the initial handshake, the server is violating the protocol and the handshake fails with alertHandshakeFailure.
Source
Thrown at src/crypto/tls/handshake_client.go:910
supportsPointFormat := false
offeredNonCompressedFormat := false
for _, format := range hs.serverHello.supportedPoints {
if format == pointFormatUncompressed {
supportsPointFormat = true
} else {
offeredNonCompressedFormat = true
}
}
if !supportsPointFormat && offeredNonCompressedFormat {
return false, errors.New("tls: server offered only incompatible point formats")
}
if c.handshakes == 0 && hs.serverHello.secureRenegotiationSupported {
c.secureRenegotiation = true
if len(hs.serverHello.secureRenegotiation) != 0 {
c.sendAlert(alertHandshakeFailure)
return false, errors.New("tls: initial handshake had non-empty renegotiation extension")
}
}
if c.handshakes > 0 && c.secureRenegotiation {
var expectedSecureRenegotiation [24]byte
copy(expectedSecureRenegotiation[:], c.clientFinished[:])
copy(expectedSecureRenegotiation[12:], c.serverFinished[:])
if !bytes.Equal(hs.serverHello.secureRenegotiation, expectedSecureRenegotiation[:]) {
c.sendAlert(alertHandshakeFailure)
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.alpnProtocolView on GitHub (pinned to b6b368adc5)
Solutions
- Patch the server to comply with RFC 5746 (empty renegotiation_info on initial handshake).
- Capture the ServerHello and report the defect to the server operator.
- Investigate the path for tampering.
Defensive patterns
Strategy: try-catch
Type guard
func isInitialHandshakeNonEmptyReneg(err error) bool {
return err != nil && strings.Contains(err.Error(), "initial handshake had non-empty renegotiation extension")
} Try / catch
if _, err := tls.Dial("tcp", addr, cfg); err != nil {
if isInitialHandshakeNonEmptyReneg(err) {
reportServerDefect(addr, err) // RFC 5746 violation
}
} Prevention
- Report RFC 5746 violations to the server operator.
- Investigate tampering on the path.
When it happens
Trigger: Server sending non-empty renegotiation_info on the initial handshake; middlebox injecting data into the extension; corrupted ServerHello.
Common situations: Custom or outdated TLS stacks; rare in practice.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- tls: incorrect renegotiation extension contents
- tls: server echoed TLS 1.3 compatibility session ID in TLS 1
- tls: server's identity changed during renegotiation
- tls: server selected unsupported compression format
- tls: invalid outer extensions
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/5b469a1ee7c54f2a.
Report an issue: GitHub.