micro/go-micro · warning
failed to close body
Error message
failed to close body
What it means
The HTTP transport client's Recv (message receive) defers a Body.Close and, if closing the response body fails, rewrites the pending error with 'failed to close body'. It signals the HTTP response body could not be cleanly closed — usually a symptom of an underlying connection/socket problem rather than a logic bug in caller code.
Source
Thrown at transport/http_client.go:159
return err
}
}
h.Lock()
defer h.Unlock()
if h.closed {
return io.EOF
}
rsp, err := http.ReadResponse(h.buff, req)
if err != nil {
return err
}
defer func() {
if err2 := rsp.Body.Close(); err2 != nil {
err = errors.Wrap(err2, "failed to close body")
}
}()
b, err := io.ReadAll(rsp.Body)
if err != nil {
return err
}
if rsp.StatusCode != http.StatusOK {
return errors.New(rsp.Status + ": " + string(b))
}
msg.Body = b
if msg.Header == nil {
msg.Header = make(map[string]string, len(rsp.Header))
}
View on GitHub (pinned to 24529f1404)
Solutions
- Inspect the wrapped cause — it usually reflects an already-dead connection; treat as a transport-level failure and retry the request.
- Enable/disable keep-alives or tune client timeouts so connections aren't severed mid-close.
- Check server/load-balancer idle timeout settings versus client usage patterns.
- Retry the receive operation; this error is typically transient.
- Verify network stability between client and the HTTP transport server.
Example fix
// before
msg, err := sock.Recv() // transient: failed to close body
if err != nil { return err }
// after
msg, err := sock.Recv()
if err != nil {
if isTransientNetErr(err) { // includes wrapped 'failed to close body'
return retry(sock.Recv)
}
return err
} Defensive patterns
Strategy: try-catch
Type guard
func isBodyCloseErr(err error) bool {
return err != nil && strings.Contains(err.Error(), "failed to close body")
} Try / catch
msg, err := client.Recv()
if err != nil {
if isBodyCloseErr(err) {
// connection already broken; log and retry
log.Warn("body close failed (dead connection)")
return retryWithBackoff(func() error { _, err = client.Recv(); return err })
}
return err
} Prevention
- Treat this as transient: retry the receive after reconnecting.
- Align client timeouts with server/LB idle timeouts to avoid severed keep-alive connections.
- Disable or tune HTTP keep-alives for long-lived streaming transports.
- Monitor network stability; this error usually accompanies connection resets.
- Check the wrapped cause via errors.Unwrap for the underlying net error.
When it happens
Trigger: Receiving a streaming/published message over the http transport when rsp.Body.Close() returns an error: connection reset by peer mid-close, already-broken socket, or server abruptly terminating the response.
Common situations: Server behind a load balancer that kills idle keep-alive connections; client timeouts cutting the connection while the body is being closed; remote service crashing during a streaming response.
Related errors
- failed request
- API error: nil response
- message passed in is nil
- ${rsp.Status}: ${body} (dynamic HTTP status and body)
- connection error
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/ac1ab3579ae73fbb.
Report an issue: GitHub.