geektutu/7days-golang · error
reading body
Error message
reading body
What it means
In the client's receive loop, when the response header indicates success the client reads the reply body into call.Reply. If codec.ReadBody fails (corrupt/truncated data, decode error), receive wraps the underlying error as "reading body " + err and stores it in call.Error, which Call then returns to the caller. It signals the reply could not be decoded, typically because the connection was broken mid-response.
Source
Thrown at gee-rpc/day5-http-debug/client.go:157
for err == nil {
var h codec.Header
if err = client.cc.ReadHeader(&h); err != nil {
break
}
call := client.removeCall(h.Seq)
switch {
case call == nil:
// it usually means that Write partially failed
// and call was already removed.
err = client.cc.ReadBody(nil)
case h.Error != "":
call.Error = fmt.Errorf(h.Error)
err = client.cc.ReadBody(nil)
call.done()
default:
err = client.cc.ReadBody(call.Reply)
if err != nil {
call.Error = errors.New("reading body " + err.Error())
}
call.done()
}
}
// error occurs, so terminateCalls pending calls
client.terminateCalls(err)
}
// Go invokes the function asynchronously.
// It returns the Call structure representing the invocation.
func (client *Client) Go(serviceMethod string, args, reply interface{}, done chan *Call) *Call {
if done == nil {
done = make(chan *Call, 10)
} else if cap(done) == 0 {
log.Panic("rpc client: done channel is unbuffered")
}
call := &Call{
ServiceMethod: serviceMethod,View on GitHub (pinned to cf36443821)
Solutions
- Retry the call; if it is transient network truncation a retry on a fresh connection usually succeeds
- Verify client and server use the same codec (MagicNumber/CodecType option agreement)
- Check server logs for crashes mid-response and fix the handler panic/error path
- Keep connections alive with heartbeats or lower idle timeouts on proxies/LBs so connections aren't silently half-closed
Example fix
// before
err := client.Call(ctx, "Foo.Sum", args, reply) // "reading body unexpected EOF"
// after
err := client.Call(ctx, "Foo.Sum", args, reply)
if err != nil && strings.HasPrefix(err.Error(), "reading body ") {
// redial and retry once on a fresh connection
client = dialNewClient()
err = client.Call(ctx, "Foo.Sum", args, reply)
} Defensive patterns
Strategy: retry
Validate before calling
// ensure codec agreement before dialing
if opt.CodecType != serverExpectedCodec {
return fmt.Errorf("codec mismatch: client %s vs server %s", opt.CodecType, serverExpectedCodec)
} Try / catch
err := client.Call(ctx, "Foo.Sum", args, reply)
if err != nil && strings.HasPrefix(err.Error(), "reading body ") {
time.Sleep(backoff)
client = dialNewClient() // fresh connection, then retry
err = client.Call(ctx, "Foo.Sum", args, reply)
} Prevention
- Retry idempotent calls on body-read failures with a fresh connection
- Keep codecs symmetric between client and server options
- Enable TCP keepalives and sane LB idle timeouts to avoid half-dead connections
- Watch for server handler panics that truncate responses
When it happens
Trigger: Network connection reset/closed while the response body is being read; codec mismatch between server and client causing decode failures; truncated payload from an intermediary; server wrote a malformed response.
Common situations: Server crashed after writing the header but before the body; firewall/proxy cutting idle connections; using different codec settings than the server; message larger than some buffer/limit on the path.
Related errors
AI-assisted analysis of geektutu/7days-golang@cf36443821 (2026-09-03).
Data as JSON: /api/errors/57b48651ce035e51.
Report an issue: GitHub.