{"record":{"id":"72687dff4506ff85","repo":"geektutu/7days-golang","slug":"reading-body-72687d","errorCode":null,"errorMessage":"reading body ","messagePattern":"reading body ","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-rpc/day7-registry/client.go","lineNumber":157,"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":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-rpc/day7-registry/client.go#L139-L175","documentation":"In the client's receive loop, reading the reply body into call.Reply failed. The underlying codec/IO error is wrapped as \"reading body \" + err, stored in call.Error, and the pending call is then terminated. This typically indicates corrupted or truncated reply data on the connection.","triggerScenarios":"Server wrote a header but the body was malformed, connection reset mid-body, reply type not decodable into call.Reply (type mismatch between client reply and server response), or server crashed while writing the response.","commonSituations":"Version/codec mismatch between client and server options, mismatched reply struct types between client and server, network interruption or proxy timeout cutting the response, or server panics mid-serialization.","solutions":["Inspect the wrapped underlying error (err.Error()) to distinguish network reset from decode failure.","Ensure client reply type matches what the server method writes into its second argument.","Verify both sides use the same codec/option (MagicNumber, CodecType); recreate the connection after this error since terminateCalls shuts the client down."],"exampleFix":"// before\ntype Reply struct{ A string }\n// server returns {\"sum\": 10} — decode fails\n// after\ntype Reply struct{ Sum int } // align reply struct with server's response","handlingStrategy":"retry","validationCode":"// ensure reply struct mirrors the server's response type\nvar _ = func() error {\n    var reply server.Reply\n    _ = &reply // keep types in a shared package to prevent drift\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := client.Call(ctx, \"Foo.Sum\", args, reply); err != nil && strings.HasPrefix(err.Error(), \"reading body\") {\n    client, _ = geeRPC.XDial(addr) // connection was terminated, rebuild and retry\n}","preventionTips":["Share request/reply types between client and server in a common package.","Match CodecType/MagicNumber options on both ends.","Set keepalives/timeouts so reset connections are detected early."],"tags":["rpc","network","deserialization","client"],"backgroundTag":"rpc-read-body-failed","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"}