{"record":{"id":"8f50ebcbd2996e9f","repo":"geektutu/7days-golang","slug":"s-8f50eb","errorCode":null,"errorMessage":"%s","messagePattern":"%s","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-rpc/day3-service/client.go","lineNumber":146,"sourceCode":"\t\t}\n\t}\n}\n\nfunc (client *Client) receive() {\n\tvar err error\n\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 {","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-rpc/day3-service/client.go#L128-L164","documentation":"Same receive-loop failure as day2 but in gee-rpc/day3-service: reading a response body failed, so the pending Call's Error becomes \"reading body <cause>\" and the client tears down the connection and all in-flight calls. It means the response stream was broken or undecodable.","triggerScenarios":"During a Call on a day3-service client, client.cc.ReadBody(call.Reply) errors: connection reset by the server, truncated response, or Gob decode mismatch between the server's written reply and the client's reply type.","commonSituations":"Server-side method panics mid-write; service registered on the server writes a reply of a different concrete type; firewall/proxy drops long-lived connections; incompatible day-branch versions (server from day2, client from day3) writing mismatched streams.","solutions":["Verify server and client use compatible versions/codecs (same MagicNumber/CodecType handshake)","Make the reply argument a non-nil pointer of the exact type the server method produces","Inspect server logs for panics during method execution","Retry the call after reconnecting; the connection is dead after this error"],"exampleFix":"// before\nvar out Foo\nclient.Call(\"Bar.Method\", req, out) // wrong: value type\n// after\nout := &Foo{}\nif err := client.Call(\"Bar.Method\", req, out); err != nil {\n\tclient, err = geerpc.Dial(\"tcp\", addr, opts) // reconnect before retry\n}","handlingStrategy":"retry","validationCode":"reply := &ExpectedType{}\nif client == nil {\n\tc, err := geerpc.Dial(\"tcp\", addr, opts)\n\tif err != nil { return err }\n\tclient = c\n}","typeGuard":"func replyIsPointer(v interface{}) bool {\n\trv := reflect.ValueOf(v)\n\treturn rv.IsValid() && rv.Kind() == reflect.Ptr && !rv.IsNil()\n}","tryCatchPattern":"err := client.Call(\"Bar.Method\", req, reply)\nif err != nil && strings.HasPrefix(err.Error(), \"reading body\") {\n\tclient, _ = geerpc.Dial(\"tcp\", addr, opts)\n\terr = client.Call(\"Bar.Method\", req, reply)\n}","preventionTips":["Use identical client/server versions of the library so codecs match","Pass pointer replies matching the server's concrete reply type","Log and alert on server panics during method execution","Reconnect after any receive-loop failure; the client is single-use after that"],"tags":["rpc","network","gob-decode","connection-dropped"],"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"}