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

  1. Retry the call; if it is transient network truncation a retry on a fresh connection usually succeeds
  2. Verify client and server use the same codec (MagicNumber/CodecType option agreement)
  3. Check server logs for crashes mid-response and fix the handler panic/error path
  4. 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

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.