grpc/grpc-go · error
reading server HTTP response: %v
Error message
reading server HTTP response: %v
What it means
This error occurs in doHTTPConnectHandshake when http.ReadResponse fails to read the proxy's response to the CONNECT request. The bufio.Reader could not parse a valid HTTP response from the proxy — the connection may have closed, timed out, or the proxy sent a non-HTTP response.
Source
Thrown at internal/transport/proxy.go:81
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 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
}View on GitHub (pinned to 03255a9237)
Solutions
- Confirm the proxy address is an HTTP/HTTPS proxy that supports CONNECT tunneling (not a SOCKS or raw TCP service).
- Check proxy logs for connection drops or errors on the target port.
- Test the proxy manually: curl -x http://proxy:port https://target to isolate gRPC vs proxy issues.
- Retry with backoff if the proxy is intermittently unreliable.
Example fix
// before (broken): pointing at a non-HTTP proxy port
os.Setenv("HTTPS_PROXY", "http://10.0.0.1:9999") // raw TCP service
// after (valid): correct HTTP proxy address
os.Setenv("HTTPS_PROXY", "http://10.0.0.1:3128") // squid/tinyproxy HTTP CONNECT Defensive patterns
Strategy: retry
Validate before calling
// Verify the proxy supports HTTP CONNECT before using it
func testProxyConnect(proxyURL, targetHost string) error {
u, err := url.Parse(proxyURL)
if err != nil { return err }
conn, err := net.DialTimeout("tcp", u.Host, 5*time.Second)
if err != nil { return err }
defer conn.Close()
req := fmt.Sprintf("CONNECT %s HTTP/1.1\r\nHost: %s\r\n\r\n", targetHost, targetHost)
_, err = conn.Write([]byte(req))
return err
} Try / catch
conn, err := grpc.Dial(target,
grpc.WithConnectParams(grpc.ConnectParams{
Backoff: backoff.Config{BaseDelay: 2*time.Second, MaxDelay: 30*time.Second},
MinConnectTimeout: 10 * time.Second,
}),
)
if err != nil {
// check if it's a proxy response read failure
if strings.Contains(err.Error(), "reading server HTTP response") {
log.Printf("proxy may not support CONNECT or is unhealthy")
}
} Prevention
- Verify the proxy address points to an HTTP proxy, not a raw TCP service.
- Test proxy connectivity independently (curl -x) before deploying gRPC clients.
- Configure backoff/retry to handle transient proxy issues.
When it happens
Trigger: After successfully writing the CONNECT request to the proxy, reading the response fails. This happens when the proxy closes the connection abruptly, sends garbage/non-HTTP data, or the connection times out before a full response is received.
Common situations: Proxy is overloaded and drops connections mid-response, proxy is not actually an HTTP proxy (e.g., pointing at a plain TCP service), TLS-intercepting proxy that resets plain CONNECT, or the proxy returns a response larger than the read buffer under network congestion.
Related errors
- failed to write the HTTP request: %v
- failed to do connect handshake, status code: %s
- failed to do connect handshake, response: %q
- transport: timeout string is too short: %q
- transport: timeout string is too long: %q
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/20671c55a2943e52.
Report an issue: GitHub.