grpc/grpc-go · error
failed to do connect handshake, response: %q
Error message
failed to do connect handshake, response: %q
What it means
This error occurs in doHTTPConnectHandshake when the proxy returns a non-200 status to the CONNECT request and the full response was successfully dumped. The dumped response (headers + body) is included for diagnostics, showing exactly why the proxy refused the tunnel.
Source
Thrown at internal/transport/proxy.go:89
p, _ := user.Password()
req.Header.Add(proxyAuthHeaderKey, "Basic "+basicAuth(u, p))
}
if err := sendHTTPRequest(ctx, req, conn); err != nil {
return nil, fmt.Errorf("failed to write the HTTP request: %v", err)
}
r := bufio.NewReader(conn)
resp, err := http.ReadResponse(r, req)
if err != nil {
return nil, fmt.Errorf("reading server HTTP response: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
dump, err := httputil.DumpResponse(resp, true)
if err != nil {
return nil, fmt.Errorf("failed to do connect handshake, status code: %s", resp.Status)
}
return nil, fmt.Errorf("failed to do connect handshake, response: %q", dump)
}
// The buffer could contain extra bytes from the target server, so we can't
// discard it. However, in many cases where the server waits for the client
// to send the first message (e.g. when TLS is being used), the buffer will
// be empty, so we can avoid the overhead of reading through this buffer.
if r.Buffered() != 0 {
return &bufConn{Conn: conn, r: r}, nil
}
return conn, nil
}
// proxyDial establishes a TCP connection to the specified address and performs an HTTP CONNECT handshake.
func proxyDial(ctx context.Context, addr resolver.Address, grpcUA string, opts proxyattributes.Options) (net.Conn, error) {
conn, err := internal.NetDialerWithTCPKeepalive().DialContext(ctx, "tcp", addr.Addr)
if err != nil {
return nil, err
}
return doHTTPConnectHandshake(ctx, conn, grpcUA, opts)View on GitHub (pinned to 03255a9237)
Solutions
- Read the dumped response in the error message to identify the proxy's refusal reason.
- For 407 responses, provide valid proxy credentials in the HTTPS_PROXY URL.
- For 502/503, ensure the target endpoint is reachable from the proxy's network.
- For 403, verify the destination is allowed by proxy access control lists.
Example fix
// before (broken): missing credentials → 407 Proxy Authentication Required
os.Setenv("HTTPS_PROXY", "http://proxy:3128")
// after (valid): embedded credentials satisfy the 407 challenge
os.Setenv("HTTPS_PROXY", "http://svcuser:s3cret@proxy:3128") Defensive patterns
Strategy: fallback
Try / catch
if strings.Contains(err.Error(), "connect handshake, response") {
// parse the dumped response for status code
// 407 → fix credentials; 502 → upstream issue; 403 → policy block
log.Printf("proxy refused CONNECT: %v", err)
// implement fallback to direct connection or alternate proxy
} Prevention
- Read the dumped response body in the error to diagnose proxy refusal.
- Keep proxy credentials current and rotated properly.
- Monitor proxy access logs for refused CONNECT requests from gRPC clients.
When it happens
Trigger: The proxy responded to CONNECT with a non-200 status (e.g., 407, 502) and httputil.DumpResponse succeeded, so the complete HTTP response including headers and body is quoted in the error message.
Common situations: Proxy authentication failure (407 with Proxy-Authenticate header), upstream connectivity issue (502 with error page), proxy access policy rejection (403). Common in corporate environments with authenticated proxies.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- failed to do connect handshake, status code: %s
- failed to write the HTTP request: %v
- reading server HTTP response: %v
- http status %d, body: %s
- empty accessToken in response (%v)
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/e7ad7d814faf663b.
Report an issue: GitHub.