{"record":{"id":"e2486f793d282648","repo":"grpc/grpc-go","slug":"failed-to-write-the-http-request-v","errorCode":null,"errorMessage":"failed to write the HTTP request: %v","messagePattern":"failed to write the HTTP request: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/transport/proxy.go","lineNumber":75,"sourceCode":"func doHTTPConnectHandshake(ctx context.Context, conn net.Conn, grpcUA string, opts proxyattributes.Options) (_ net.Conn, err error) {\n\tdefer func() {\n\t\tif err != nil {\n\t\t\tconn.Close()\n\t\t}\n\t}()\n\n\treq := &http.Request{\n\t\tMethod: http.MethodConnect,\n\t\tURL:    &url.URL{Host: opts.ConnectAddr},\n\t\tHeader: map[string][]string{\"User-Agent\": {grpcUA}},\n\t}\n\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","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/transport/proxy.go#L57-L93","documentation":"Fires in doHTTPConnectHandshake (proxy.go:75) when sendHTTPRequest fails to write the HTTP CONNECT request to the proxy connection. gRPC builds a CONNECT request (with optional Proxy-Authorization) and writes it to the TCP connection established to the proxy; if that write fails the handshake aborts and the connection is closed.","triggerScenarios":"Setting HTTPS_PROXY/HTTP_PROXY (or WithContextDialer proxy config) and the write to the proxy socket fails. Causes: the proxy closed/reset the connection immediately after TCP connect, a network drop mid-write, a broken pipe because the proxy rejected the client, or the context was cancelled before/during the write.","commonSituations":"Misconfigured or unreachable HTTP proxy; proxy that immediately drops CONNECT to non-allowlisted hosts; transient network instability between client and proxy; cancelled/timed-out dial context; proxy requiring TLS but reached as plain TCP.","solutions":["Verify the proxy address from HTTPS_PROXY/HTTP_PROXY (or grpc.WithContextDialer) resolves and accepts TCP connections.","Check the proxy's logs/rules: it may be rejecting CONNECT to the target host or requiring authentication you didn't supply.","Ensure the dial context has a generous-enough deadline; a too-short timeout can abort the write.","If the proxy requires a TLS connection first, use an https:// proxy URL so Go dials TLS to the proxy before CONNECT."],"exampleFix":"// before: proxy env points at a proxy that resets CONNECT\n//   HTTPS_PROXY=http://broken-proxy:3128\n\n// after: correct, reachable proxy with auth\nimport (\n    _ \"google.golang.org/grpc/credentials/insecure\"\n)\nos.Setenv(\"HTTPS_PROXY\", \"http://user:pass@real-proxy:3128\")\nconn, err := grpc.NewClient(target, grpc.WithTransportCredentials(creds))","handlingStrategy":"try-catch","validationCode":"// Verify proxy reachability before dialing gRPC.\nfunc proxyReachable(proxyURL string) error {\n    u, err := url.Parse(proxyURL)\n    if err != nil {\n        return err\n    }\n    c, err := net.DialTimeout(\"tcp\", u.Host, 2*time.Second)\n    if err != nil {\n        return err\n    }\n    c.Close()\n    return nil\n}","typeGuard":null,"tryCatchPattern":"conn, err := grpc.NewClient(target, opts...)\n// proxy write failures surface during the first RPC or Dial.\n// Wrap with a retry on transient network errors.\nif err != nil {\n    if isTransient(err) {\n        // back off and retry NewClient / the RPC\n    }\n}","preventionTips":["Validate HTTPS_PROXY/HTTP_PROXY at startup with a connectivity check.","Give the dial context a generous deadline.","Use https:// proxy URLs when the proxy requires TLS."],"tags":["proxy","network","connect","http2","transport"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}