{"record":{"id":"b1d296d81eedfb0e","repo":"geektutu/7days-golang","slug":"s-b1d296","errorCode":null,"errorMessage":"%s","messagePattern":"%s","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-rpc/day4-timeout/client.go","lineNumber":148,"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":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-rpc/day4-timeout/client.go#L130-L166","documentation":"In gee-rpc/day4-timeout's receive loop, a failure reading the response body sets the Call's Error to \"reading body <cause>\" and terminates the connection and every pending call. The timeout additions on the client do not change this path: it is still a broken/undecodable response stream.","triggerScenarios":"A Call/Go on a day4-timeout client gets a header but ReadBody fails: server closed the connection after the header, response truncated (possibly by a timeout handler closing the conn), or reply decode type mismatch.","commonSituations":"Server-side handler timeout closes the socket mid-response; client-side Call timeout abandons the call while the server is still writing; reply pointer type mismatch; server panic during serialization.","solutions":["Align ConnectTimeout/HandleTimeout on the server and client so neither side drops the connection mid-response","Pass a correct non-nil pointer reply matching the server's reply type","Check server logs for panics or forced connection closes","Retry with a fresh Dial after this error; the old client is unusable"],"exampleFix":"// before\nclient, _ := geerpc.Dial(\"tcp\", addr, opt) // opt timeouts too small\nerr := client.Call(\"Foo.Sum\", req, reply)\n// after\nopt := &geerpc.Option{ConnectTimeout: 5 * time.Second, HandleTimeout: 10 * time.Second}\nclient, err := geerpc.Dial(\"tcp\", addr, opt)\nerr = client.Call(\"Foo.Sum\", req, &reply)","handlingStrategy":"retry","validationCode":"opt := &geerpc.Option{ConnectTimeout: 5 * time.Second, HandleTimeout: 10 * time.Second}\nif opt.HandleTimeout <= opt.ConnectTimeout { /* server may close mid-response; adjust */ }","typeGuard":"func replyIsPointer(v interface{}) bool {\n\trv := reflect.ValueOf(v)\n\treturn rv.IsValid() && rv.Kind() == reflect.Ptr && !rv.IsNil()\n}","tryCatchPattern":"if err := client.Call(\"Foo.Sum\", req, reply); err != nil {\n\tif strings.HasPrefix(err.Error(), \"reading body\") {\n\t\tclient, err = geerpc.Dial(\"tcp\", addr, opt)\n\t\tif err == nil { err = client.Call(\"Foo.Sum\", req, reply) }\n\t}\n}","preventionTips":["Set HandleTimeout generously larger than ConnectTimeout and expected method latency","Always pass a pointer reply of the exact server type","Check server logs for panics or forced closes after timeouts","Treat this error as fatal to the connection: dial a fresh client before retrying"],"tags":["rpc","network","timeout","gob-decode"],"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"}