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

  1. Ensure reply passed to Call is a non-nil pointer whose type matches what the server handler writes
  2. Keep request/response struct definitions in a shared package so both sides agree
  3. Inspect the wrapped underlying error (suffix of the message) for the codec's real cause
  4. 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

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


AI-assisted analysis of geektutu/7days-golang@cf36443821 (2026-09-03). Data as JSON: /api/errors/6b1da3cbcd6f2049. Report an issue: GitHub.