geektutu/7days-golang · error
reading body
Error message
reading body
What it means
In receive(), after a successful header the client reads the response body into call.Reply; if ReadBody fails, the call's Error is set to "reading body " + the underlying error. This means the response header arrived but the payload could not be decoded or read. The connection is then terminated and pending calls are cleaned up.
Source
Thrown at gee-rpc/day6-load-balance/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
- Ensure reply passed to Call is a non-nil pointer whose type matches what the server handler writes
- Keep request/response struct definitions in a shared package so both sides agree
- Inspect the wrapped underlying error (suffix of the message) for the codec's real cause
- Reconnect and retry: the connection was terminated after this error
Example fix
// before
var reply map[string]int // mismatched with server's []string response
client.Call(ctx, "Foo.Bar", args, &reply)
// after
type FooBarReply struct { Items []string }
reply := &FooBarReply{}
if err := client.Call(ctx, "Foo.Bar", args, reply); err != nil { ... } Defensive patterns
Strategy: validation
Validate before calling
// ensure reply is a non-nil pointer before calling
func validateReply(reply interface{}) error {
rv := reflect.ValueOf(reply)
if rv.Kind() != reflect.Ptr || rv.IsNil() {
return errors.New("reply must be a non-nil pointer")
}
return nil
} Try / catch
if err := client.Call(ctx, "Foo.Bar", args, reply); err != nil {
if strings.HasPrefix(err.Error(), "reading body ") {
// log strings.TrimPrefix(err.Error(), "reading body ") for the codec cause; reconnect
}
} Prevention
- Share request/reply struct definitions between client and server via a common package
- Always pass a pointer as reply and keep its type aligned with the handler's output
- Bump protocol/codec versions together on both sides when changing message shapes
- Log the wrapped underlying error to distinguish decode failures from truncated reads
When it happens
Trigger: Codec cannot decode the body into the caller's reply type (type mismatch between client reply and server handler's out parameter); truncated/corrupted body on the wire; server wrote a body with a different codec than negotiated.
Common situations: Reply argument is a non-pointer or a type incompatible with the server's response; mismatched struct definitions between client and server after an API change; network interruption mid-response.
Related errors
- reading body
- reading body
- rpc client: call failed:
- number of options is more than 1
- rpc server: service/method request ill-formed:
AI-assisted analysis of geektutu/7days-golang@cf36443821 (2026-09-03).
Data as JSON: /api/errors/6b1da3cbcd6f2049.
Report an issue: GitHub.