grpc/grpc-go · error
failed to write the HTTP request: %v
Error message
failed to write the HTTP request: %v
What it means
This error occurs in doHTTPConnectHandshake when sendHTTPRequest fails to write the HTTP CONNECT request to the proxy connection. The underlying conn.Write returned an error, indicating the TCP connection to the proxy was broken or the write was interrupted.
Source
Thrown at internal/transport/proxy.go:75
func doHTTPConnectHandshake(ctx context.Context, conn net.Conn, grpcUA string, opts proxyattributes.Options) (_ net.Conn, err error) {
defer func() {
if err != nil {
conn.Close()
}
}()
req := &http.Request{
Method: http.MethodConnect,
URL: &url.URL{Host: opts.ConnectAddr},
Header: map[string][]string{"User-Agent": {grpcUA}},
}
if user := opts.User; user != nil {
u := user.Username()
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 willView on GitHub (pinned to 03255a9237)
Solutions
- Verify the proxy address is reachable and the proxy process is running.
- Check network connectivity/firewall rules between the client and the proxy host:port.
- Retry the connection (transient proxy/network issues often resolve on retry).
- If the context deadline is too short, increase the dial timeout with grpc.WithTransportCredentials + context.WithTimeout.
Example fix
// before (broken): no retry on transient proxy write failure
conn, err := grpc.Dial(target, grpc.WithBlock())
// after (valid): use a dial timeout and retry/backoff policy
conn, err := grpc.Dial(target,
grpc.WithConnectParams(grpc.ConnectParams{
Backoff: backoff.Config{BaseDelay: 1*time.Second, MaxDelay: 10*time.Second},
MinConnectTimeout: 5 * time.Second,
}),
) Defensive patterns
Strategy: retry
Try / catch
// gRPC client connection with retry/backoff handles transient proxy write failures
conn, err := grpc.Dial(target,
grpc.WithConnectParams(grpc.ConnectParams{
Backoff: backoff.Config{BaseDelay: 1*time.Second, MaxDelay: 30*time.Second, Multiplier: 1.6},
MinConnectTimeout: 5 * time.Second,
}),
)
if err != nil {
log.Printf("failed to connect via proxy: %v", err)
} Prevention
- Configure grpc.ConnectParams with appropriate backoff for proxy environments.
- Monitor proxy health and configure failover if possible.
- Set reasonable dial timeouts to avoid hanging on unreachable proxies.
When it happens
Trigger: Calling grpc.Dial with a proxy configured (HTTPS_PROXY/HTTPS_PROXY env var or WithContextDialer proxy), and the TCP connection to the proxy drops before or during the CONNECT request write — e.g., proxy process crashed, network partition, or the dial context was cancelled.
Common situations: Corporate proxy restarts/failures, flaky network between client and forward proxy, proxy rejecting connections at the TCP level (connection reset), or context cancellation (deadline exceeded) during proxy handshake.
Related errors
- reading server HTTP response: %v
- failed to do connect handshake, status code: %s
- failed to do connect handshake, response: %q
- keepalive ping not acked within timeout %s
- last connection error: %v
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/e2486f793d282648.
Report an issue: GitHub.