Error message
remote error: tls: handshake failure
In HTTP clients the line reads "Get \"https://…\": remote error: tls: handshake failure". Go uses the same "remote error: tls: <alert>" form on servers, in "http: TLS handshake error from …" log lines, when a client sends an alert.
Go crypto/tls client — the server sent TLS alert 40 (handshake_failure)
What it means
"remote error" means the other side sent a TLS alert; here the server sent alert 40 (handshake_failure) to the Go client. The server rejected the parameters Go offered (cipher suites, groups, signature algorithms) or required a client certificate that Go did not send. Go cannot tell which; the server's log can.
Why it happens
No common cipher suite
commonGo's default client list has no RSA-key-exchange, CBC or 3DES suites; servers limited to those have nothing in common with it.
The server requires a client certificate
commonTLS 1.2 servers in mutual-TLS mode often answer a missing certificate with handshake_failure.
SNI not accepted
occasionalDialing by IP without ServerName, or a name the server does not serve, can trigger the alert on CDNs and proxies.
How to fix it
- 1.
Compare cipher suites
tls.CipherSuites() lists what Go considers secure and offers; compare with the server's configuration.
go // What does this Go client offer by default? for _, s := range tls.CipherSuites() { fmt.Println(s.Name) } - 2.
Send a client certificate for mutual TLS
Load the certificate and key with tls.LoadX509KeyPair and set them in tls.Config.Certificates.
go // Mutual TLS: present a client certificate cert, err := tls.LoadX509KeyPair("client.pem", "client.key") if err != nil { log.Fatal(err) } client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{ Certificates: []tls.Certificate{cert}, }}} - 3.
Server owners: modernise the suites
TLS 1.3 and ECDHE-based TLS 1.2 suites work with every current Go release.
text Server side: enable TLS 1.3 and TLS 1.2 ECDHE suites with AES-GCM or ChaCha20-Poly1305.