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

  1. Inspect the wrapped cause — it usually reflects an already-dead connection; treat as a transport-level failure and retry the request.
  2. Enable/disable keep-alives or tune client timeouts so connections aren't severed mid-close.
  3. Check server/load-balancer idle timeout settings versus client usage patterns.
  4. Retry the receive operation; this error is typically transient.
  5. 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

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


AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/ac1ab3579ae73fbb. Report an issue: GitHub.