{"record":{"id":"e7ad7d814faf663b","repo":"grpc/grpc-go","slug":"failed-to-do-connect-handshake-response-q","errorCode":null,"errorMessage":"failed to do connect handshake, response: %q","messagePattern":"failed to do connect handshake, response: %q","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/transport/proxy.go","lineNumber":89,"sourceCode":"\t\tp, _ := user.Password()\n\t\treq.Header.Add(proxyAuthHeaderKey, \"Basic \"+basicAuth(u, p))\n\t}\n\tif err := sendHTTPRequest(ctx, req, conn); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to write the HTTP request: %v\", err)\n\t}\n\n\tr := bufio.NewReader(conn)\n\tresp, err := http.ReadResponse(r, req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"reading server HTTP response: %v\", err)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\tdump, err := httputil.DumpResponse(resp, true)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to do connect handshake, status code: %s\", resp.Status)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"failed to do connect handshake, response: %q\", dump)\n\t}\n\t// The buffer could contain extra bytes from the target server, so we can't\n\t// discard it. However, in many cases where the server waits for the client\n\t// to send the first message (e.g. when TLS is being used), the buffer will\n\t// be empty, so we can avoid the overhead of reading through this buffer.\n\tif r.Buffered() != 0 {\n\t\treturn &bufConn{Conn: conn, r: r}, nil\n\t}\n\treturn conn, nil\n}\n\n// proxyDial establishes a TCP connection to the specified address and performs an HTTP CONNECT handshake.\nfunc proxyDial(ctx context.Context, addr resolver.Address, grpcUA string, opts proxyattributes.Options) (net.Conn, error) {\n\tconn, err := internal.NetDialerWithTCPKeepalive().DialContext(ctx, \"tcp\", addr.Addr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn doHTTPConnectHandshake(ctx, conn, grpcUA, opts)","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/transport/proxy.go#L71-L107","documentation":"Fires in doHTTPConnectHandshake (proxy.go:89) when the proxy returns a non-200 status to CONNECT and the response was successfully dumped for diagnostics. gRPC expects HTTP/1.1 200 OK after a CONNECT; any other status means the proxy refused to establish the tunnel, and the full dumped response (status line, headers, body) is included so the reason is visible.","triggerScenarios":"The proxy replies to CONNECT with a status other than 200. Common: 407 Proxy Authentication Required (missing/bad credentials), 403 Forbidden (host not allowlisted), 502 Bad Gateway / 503 Service Unavailable (proxy couldn't reach upstream), 504 Gateway Timeout. The dumped %q shows headers like Proxy-Authenticate and any error body.","commonSituations":"Corporate/egress proxy requiring credentials not supplied; proxy ACL blocking the target host/port; proxy can't reach the upstream (network partition); proxy rate-limiting or overloaded; mismatch between the proxy's expectations and the CONNECT target.","solutions":["Read the dumped response: a 407 means add Proxy-Authorization (set user:pass in the proxy URL); 403 means ask the proxy admin to allowlist the host; 502/503/504 indicate proxy-to-upstream problems.","Provide credentials via the proxy URL: https://user:pass@proxy:3128, or set Proxy-Authorization through grpc.WithContextDialer.","Verify the target address and port are correct and reachable from the proxy's network.","If you don't need the proxy, unset HTTPS_PROXY/HTTP_PROXY for the target host."],"exampleFix":"// before\n//   HTTPS_PROXY=http://proxy.corp:3128   // no creds -> 407 Proxy Authentication Required\n\n// after\nos.Setenv(\"HTTPS_PROXY\", \"http://alice:s3cr3t@proxy.corp:3128\")\n// or, for hosts that shouldn't use the proxy:\nos.Setenv(\"NO_PROXY\", \"internal-svc.cluster.local\")","handlingStrategy":"retry","validationCode":"// Build a proxy URL with credentials if the proxy requires auth.\nfunc proxyWithCreds(host, user, pass string) string {\n    u := &url.URL{Scheme: \"http\", Host: host}\n    if user != \"\" {\n        u.User = url.UserPassword(user, pass)\n    }\n    return u.String()\n}","typeGuard":null,"tryCatchPattern":"if err := dialViaProxy(...); err != nil {\n    s := err.Error()\n    if strings.Contains(s, \"407\") { /* add Proxy-Authorization */ }\n    if strings.Contains(s, \"403\") { /* request allowlist */ }\n    if strings.Contains(s, \"502\") || strings.Contains(s, \"503\") { /* backoff + retry */ }\n}","preventionTips":["Include user:pass in the proxy URL for authenticated proxies.","Use NO_PROXY for hosts that must bypass the proxy.","Verify the target address/port are reachable from the proxy network."],"tags":["proxy","network","connect","http","transport","authentication"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}