{"record":{"id":"57b48651ce035e51","repo":"geektutu/7days-golang","slug":"reading-body-57b486","errorCode":null,"errorMessage":"reading body ","messagePattern":"reading body ","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-rpc/day5-http-debug/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/day5-http-debug/client.go#L139-L175","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Retry the call; if it is transient network truncation a retry on a fresh connection usually succeeds","Verify client and server use the same codec (MagicNumber/CodecType option agreement)","Check server logs for crashes mid-response and fix the handler panic/error path","Keep connections alive with heartbeats or lower idle timeouts on proxies/LBs so connections aren't silently half-closed"],"exampleFix":"// before\nerr := client.Call(ctx, \"Foo.Sum\", args, reply) // \"reading body unexpected EOF\"\n\n// after\nerr := client.Call(ctx, \"Foo.Sum\", args, reply)\nif err != nil && strings.HasPrefix(err.Error(), \"reading body \") {\n\t// redial and retry once on a fresh connection\n\tclient = dialNewClient()\n\terr = client.Call(ctx, \"Foo.Sum\", args, reply)\n}","handlingStrategy":"retry","validationCode":"// ensure codec agreement before dialing\nif opt.CodecType != serverExpectedCodec {\n\treturn fmt.Errorf(\"codec mismatch: client %s vs server %s\", opt.CodecType, serverExpectedCodec)\n}","typeGuard":null,"tryCatchPattern":"err := client.Call(ctx, \"Foo.Sum\", args, reply)\nif err != nil && strings.HasPrefix(err.Error(), \"reading body \") {\n\ttime.Sleep(backoff)\n\tclient = dialNewClient() // fresh connection, then retry\n\terr = client.Call(ctx, \"Foo.Sum\", args, reply)\n}","preventionTips":["Retry idempotent calls on body-read failures with a fresh connection","Keep codecs symmetric between client and server options","Enable TCP keepalives and sane LB idle timeouts to avoid half-dead connections","Watch for server handler panics that truncate responses"],"tags":["rpc","codec","network","deserialization","go"],"backgroundTag":"response-body-read-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"}