golang/go · error
tls: unexpected encrypted client hello extension in serverHe
Error message
tls: unexpected encrypted client hello extension in serverHello
What it means
Thrown during HelloRetryRequest processing when the server includes an encrypted_client_hello extension in the ServerHello but the client has no ECH context (hs.echContext is nil). This means the client did not send ECH, so the server's ECH extension is unsolicited.
Source
Thrown at src/crypto/tls/handshake_client_tls13.go:289
c.sendAlert(alertInternalError)
return err
}
acceptConfirmation := tls13.ExpandLabel(h, prk, "hrr ech accept confirmation", confTranscript.Sum(nil), 8)
if subtle.ConstantTimeCompare(acceptConfirmation, hs.serverHello.encryptedClientHello) == 1 {
hello = hs.echContext.innerHello
c.serverName = c.config.ServerName
isInnerHello = true
c.echAccepted = true
}
}
if err := transcriptMsg(hs.serverHello, hs.echContext.innerTranscript); err != nil {
return err
}
} else if hs.serverHello.encryptedClientHello != nil {
// Unsolicited ECH extension should be rejected
c.sendAlert(alertUnsupportedExtension)
return errors.New("tls: unexpected encrypted client hello extension in serverHello")
}
// The only HelloRetryRequest extensions we support are key_share and
// cookie, and clients must abort the handshake if the HRR would not result
// in any change in the ClientHello.
if hs.serverHello.selectedGroup == 0 && hs.serverHello.cookie == nil {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: server sent an unnecessary HelloRetryRequest message")
}
if hs.serverHello.cookie != nil {
hello.cookie = hs.serverHello.cookie
}
if hs.serverHello.serverShare.group != 0 {
c.sendAlert(alertDecodeError)
return errors.New("tls: received malformed key_share extension")
}View on GitHub (pinned to b6b368adc5)
Solutions
- If you want ECH support, set config.EncryptedClientHelloConfigList with valid ECH configuration records from DNS HTTPS/SVCB records.
- If you do not need ECH, this is a server bug — the server should not send an unsolicited encrypted_client_hello extension.
- Report the issue to the server operator with details of the unexpected extension.
- Test with ECH disabled on a known-good server to rule out client-side issues.
Example fix
// before — no ECH config but server expects it
config := &tls.Config{
ServerName: "example.com",
}
// after — provide ECH config list from DNS HTTPS records
config := &tls.Config{
ServerName: "example.com",
EncryptedClientHelloConfigList: echConfigList, // from DNS HTTPS RR
} Defensive patterns
Strategy: validation
Validate before calling
// Validate ECH context before connecting
func validateECHPresence(config *tls.Config) error {
// If the server is known to expect ECH, ensure the config list is set
if config.EncryptedClientHelloConfigList == nil {
// Not an error per se, but warn if connecting to an ECH-capable server
log.Println("warning: no ECH config list set; servers expecting ECH will fail")
}
return nil
} Try / catch
conn, err := tls.Dial("tcp", addr, config)
if err != nil {
if strings.Contains(err.Error(), "unexpected encrypted client hello extension in serverHello") {
// Server sent unsolicited ECH — this is a server bug, nothing the client can fix
log.Printf("server sent unsolicited ECH extension: %v", err)
}
} Prevention
- Fetch ECHConfigList from DNS HTTPS/SVCB records before connecting to ECH-capable servers.
- Report servers sending unsolicited ECH extensions to the operator.
- Test with ECH disabled to confirm the error source.
When it happens
Trigger: Triggered in the else-if branch when hs.echContext is nil and hs.serverHello.encryptedClientHello is not nil. The client sends alertUnsupportedExtension.
Common situations: Server sending an ECH extension without the client having requested it. Client config does not set EncryptedClientHelloConfigList but the server responds with ECH. Server bug or misconfiguration sending unsolicited ECH extension.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- tls: unexpected encrypted client hello extension in server h
- tls: server sent encrypted client hello retry configs after
- tls: server selected TLS 1.3 in a renegotiation
- tls: unexpected server_name extension in server hello
- tls: server selected TLS 1.3 using the legacy version field
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/0378ce4dc22cab4c.
Report an issue: GitHub.