{"record":{"id":"43c42eb7aa83b591","repo":"geektutu/7days-golang","slug":"reading-body","errorCode":null,"errorMessage":"reading body ","messagePattern":"reading body ","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-rpc/day2-client/client.go","lineNumber":152,"sourceCode":"\tfor err == nil {\n\t\tvar h codec.Header\n\t\tif err = client.cc.ReadHeader(&h); err != nil {\n\t\t\tbreak\n\t\t}\n\t\tcall := client.removeCall(h.Seq)\n\t\tswitch {\n\t\tcase call == nil:\n\t\t\t// it usually means that Write partially failed\n\t\t\t// and call was already removed.\n\t\t\terr = client.cc.ReadBody(nil)\n\t\tcase h.Error != \"\":\n\t\t\tcall.Error = fmt.Errorf(h.Error)\n\t\t\terr = client.cc.ReadBody(nil)\n\t\t\tcall.done()\n\t\tdefault:\n\t\t\terr = client.cc.ReadBody(call.Reply)\n\t\t\tif err != nil {\n\t\t\t\tcall.Error = errors.New(\"reading body \" + err.Error())\n\t\t\t}\n\t\t\tcall.done()\n\t\t}\n\t}\n\t// error occurs, so terminateCalls pending calls\n\tclient.terminateCalls(err)\n}\n\n// Go invokes the function asynchronously.\n// It returns the Call structure representing the invocation.\nfunc (client *Client) Go(serviceMethod string, args, reply interface{}, done chan *Call) *Call {\n\tif done == nil {\n\t\tdone = make(chan *Call, 10)\n\t} else if cap(done) == 0 {\n\t\tlog.Panic(\"rpc client: done channel is unbuffered\")\n\t}\n\tcall := &Call{\n\t\tServiceMethod: serviceMethod,","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-rpc/day2-client/client.go#L134-L170","documentation":"In receive(), the response header parsed OK but reading the reply body into call.Reply failed, so the call is failed with \"reading body \" + err.Error(). Typically the connection broke mid-response or the body doesn't fit/match the expected type.","triggerScenarios":"Server closes the connection after writing the header; network reset/EOF mid-body; codec cannot decode the body into call.Reply (type mismatch, wrong gob type registration); server crashed mid-response.","commonSituations":"Server panics while writing a large response; reply struct not gob.Register()ed causing decode errors; idle connections killed by a load balancer; passing a nil or wrong-typed Reply pointer.","solutions":["Retry the call on a fresh connection (the client terminates pending calls on this error)","Register reply types with gob.Register on both sides if decode errors appear after \"reading body \"\nEnsure Reply is a non-nil pointer to the correct struct","Check server logs for panics/truncation during response write"],"exampleFix":"// before\ncall := client.Go(\"Foo.Sum\", args, nil, nil).Done // nil reply -> body read fails\n// after\nreply := new(FooSumReply)\ncall := client.Go(\"Foo.Sum\", args, reply, nil).Done","handlingStrategy":"retry","validationCode":"if reflect.ValueOf(reply).Kind() != reflect.Ptr || reflect.ValueOf(reply).IsNil() {\n    return errors.New(\"reply must be a non-nil pointer\")\n}","typeGuard":null,"tryCatchPattern":"if err := client.Call(method, args, reply); err != nil {\n    if strings.HasPrefix(err.Error(), \"reading body \") {\n        // decode/transport issue: re-dial and retry once; check gob registration\n        return retryOnFreshConn(method, args, reply)\n    }\n    return err\n}","preventionTips":["gob.Register all reply types on client and server","Always pass non-nil pointers for Reply","Configure keepalives to survive LB idle timeouts","Check server logs for mid-response panics/truncation"],"tags":["rpc","network","deserialization"],"backgroundTag":"rpc-response-read-error","analyzedSha":"cf3644382101dc13e7fd92e8f5c66cabc51bcd3b","analyzedAt":"2026-09-03T18:31:24.087Z","contentChangedAt":"2026-09-03T18:31:24.087Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}