golang/go · error
tls: MaxVersion must be >= VersionTLS13 if EncryptedClientHe
Error message
tls: MaxVersion must be >= VersionTLS13 if EncryptedClientHelloConfigList is populated
What it means
Thrown by makeClientHello when config.EncryptedClientHelloConfigList is non-nil (ECH is enabled on the client) AND config.MaxVersion is explicitly set to VersionTLS12 (0x0303) or below. ECH requires TLS 1.3+, so capping the maximum version at 1.2 makes ECH impossible. This check fires when MaxVersion != 0 and MaxVersion <= VersionTLS12.
Source
Thrown at src/crypto/tls/handshake_client.go:180
if c.quic != nil {
p, err := c.quicGetTransportParameters()
if err != nil {
return nil, nil, nil, err
}
if p == nil {
p = []byte{}
}
hello.quicTransportParameters = p
}
var ech *echClientContext
if c.config.EncryptedClientHelloConfigList != nil {
if c.config.MinVersion != 0 && c.config.MinVersion < VersionTLS13 {
return nil, nil, nil, errors.New("tls: MinVersion must be >= VersionTLS13 if EncryptedClientHelloConfigList is populated")
}
if c.config.MaxVersion != 0 && c.config.MaxVersion <= VersionTLS12 {
return nil, nil, nil, errors.New("tls: MaxVersion must be >= VersionTLS13 if EncryptedClientHelloConfigList is populated")
}
echConfigs, err := parseECHConfigList(c.config.EncryptedClientHelloConfigList)
if err != nil {
return nil, nil, nil, err
}
echConfig, echPK, kdf, aead := pickECHConfig(echConfigs)
if echConfig == nil {
return nil, nil, nil, errors.New("tls: EncryptedClientHelloConfigList contains no valid configs")
}
ech = &echClientContext{config: echConfig, kdfID: kdf.ID(), aeadID: aead.ID()}
hello.encryptedClientHello = []byte{1} // indicate inner hello
// We need to explicitly set these 1.2 fields to nil, as we do not
// marshal them when encoding the inner hello, otherwise transcripts
// will later mismatch.
hello.supportedPoints = nil
hello.ticketSupported = false
hello.secureRenegotiationSupported = false
hello.extendedMasterSecret = falseView on GitHub (pinned to b6b368adc5)
Solutions
- Set MaxVersion to tls.VersionTLS13 (or leave it as 0 for the default maximum, which includes TLS 1.3)
- Remove the MaxVersion cap entirely if ECH is required — ECH cannot work with a TLS 1.2 ceiling
- If you genuinely need TLS 1.2 as the maximum version, do not enable ECH — they are incompatible
Example fix
// before
config := &tls.Config{
EncryptedClientHelloConfigList: echConfigList,
MaxVersion: tls.VersionTLS12,
}
// after
config := &tls.Config{
EncryptedClientHelloConfigList: echConfigList,
MaxVersion: tls.VersionTLS13,
} Defensive patterns
Strategy: validation
Validate before calling
func validateECHClientConfig(config *tls.Config) error {
if config.EncryptedClientHelloConfigList == nil {
return nil
}
if config.MinVersion != 0 && config.MinVersion < tls.VersionTLS13 {
return errors.New("MinVersion must be >= VersionTLS13 when ECH is enabled")
}
if config.MaxVersion != 0 && config.MaxVersion <= tls.VersionTLS12 {
return errors.New("MaxVersion must be >= VersionTLS13 when ECH is enabled")
}
return nil
} Try / catch
// Pre-validate before dial:
//
// if err := validateECHClientConfig(config); err != nil {
// config.MaxVersion = 0 // reset to default (allows TLS 1.3)
// } Prevention
- Leave MaxVersion unset (0) or set it to tls.VersionTLS13 when using ECH
- Never set MaxVersion to VersionTLS12 or below when ECH is enabled
- Validate the full ECH + version configuration in a constructor function
When it happens
Trigger: Setting both EncryptedClientHelloConfigList (to a non-nil byte slice) and MaxVersion to VersionTLS12 (0x0303), VersionTLS11 (0x0302), or VersionTLS10 (0x0301) simultaneously.
Common situations: Configuring ECH while keeping MaxVersion=VersionTLS12 for legacy server compatibility. Adding ECH to a config designed for TLS 1.2-only environments. Copying a config with a TLS 1.2 ceiling and enabling ECH without raising MaxVersion.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- tls: MinVersion must be >= VersionTLS13 if EncryptedClientHe
- tls: client sent encrypted_client_hello extension with unsup
- tls: client sent encrypted_client_hello extension but did no
- tls: no supported versions satisfy MinVersion and MaxVersion
- tls: no supported key exchange methods (CurveIDs)
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/1060f321cbd02dbd.
Report an issue: GitHub.