{"record":{"id":"64443bd685d78381","repo":"grpc/grpc-go","slug":"failed-to-do-connect-handshake-status-code-s","errorCode":null,"errorMessage":"failed to do connect handshake, status code: %s","messagePattern":"failed to do connect handshake, status code: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/transport/proxy.go","lineNumber":87,"sourceCode":"\tif user := opts.User; user != nil {\n\t\tu := user.Username()\n\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","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/transport/proxy.go#L69-L105","documentation":"Fires in doHTTPConnectHandshake (proxy.go:87) on a double-failure path: the proxy returned a non-200 status to CONNECT, and additionally httputil.DumpResponse failed to serialize the response body for diagnostics. Because the dump failed, gRPC falls back to reporting only the status code (resp.Status) rather than the full response.","triggerScenarios":"The proxy rejects CONNECT (status != 200) and the response body cannot be dumped: e.g. the body read errors mid-dump (connection reset), the body is malformed, or DumpResponse encounters an unexpected state. The message shows the HTTP status text, e.g. '502 Bad Gateway' or '407 Proxy Authentication Required'.","commonSituations":"A proxy returning an error page whose body stream then breaks; an intermediary that resets the connection right after sending a non-200 status; rare compared to error 339 (which fires when the dump succeeds). The root cause is still a rejected CONNECT; the dump failure just reduces diagnostics.","solutions":["Treat this like a proxy rejection: the status code in the message tells you why (407 = auth, 403 = forbidden, 502/503 = upstream unavailable).","Supply correct proxy credentials (Proxy-Authorization / proxy URL user:pass) for 407 responses.","Confirm the target host is on the proxy's allowlist for CONNECT.","Reproduce with curl -v --proxy <url> https://<target> to see the full proxy exchange and any body."],"exampleFix":"// before: proxy requires auth, none supplied -> 407, dump fails\n//   HTTPS_PROXY=http://proxy:3128\n\n// after: include credentials in the proxy URL\nos.Setenv(\"HTTPS_PROXY\", \"http://user:pass@proxy:3128\")","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := dialViaProxy(...); err != nil {\n    if strings.Contains(err.Error(), \"connect handshake, status code\") {\n        // proxy refused CONNECT; check creds/allowlist, then retry or fail over\n    }\n}","preventionTips":["Supply proxy credentials via the proxy URL when 407 is reported.","Ensure target hosts are on the proxy's CONNECT allowlist.","Reproduce with curl -v --proxy to inspect the proxy exchange."],"tags":["proxy","network","connect","http","transport"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}