{"record":{"id":"1acc394ecd4e7b2f","repo":"geektutu/7days-golang","slug":"rpc-client-call-failed","errorCode":null,"errorMessage":"rpc client: call failed: ","messagePattern":"rpc client: call failed: ","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-rpc/day4-timeout/client.go","lineNumber":188,"sourceCode":"\t}\n\tcall := &Call{\n\t\tServiceMethod: serviceMethod,\n\t\tArgs:          args,\n\t\tReply:         reply,\n\t\tDone:          done,\n\t}\n\tclient.send(call)\n\treturn call\n}\n\n// Call invokes the named function, waits for it to complete,\n// and returns its error status.\nfunc (client *Client) Call(ctx context.Context, serviceMethod string, args, reply interface{}) error {\n\tcall := client.Go(serviceMethod, args, reply, make(chan *Call, 1))\n\tselect {\n\tcase <-ctx.Done():\n\t\tclient.removeCall(call.Seq)\n\t\treturn errors.New(\"rpc client: call failed: \" + ctx.Err().Error())\n\tcase call := <-call.Done:\n\t\treturn call.Error\n\t}\n}\n\nfunc parseOptions(opts ...*Option) (*Option, error) {\n\t// if opts is nil or pass nil as parameter\n\tif len(opts) == 0 || opts[0] == nil {\n\t\treturn DefaultOption, nil\n\t}\n\tif len(opts) != 1 {\n\t\treturn nil, errors.New(\"number of options is more than 1\")\n\t}\n\topt := opts[0]\n\topt.MagicNumber = DefaultOption.MagicNumber\n\tif opt.CodecType == \"\" {\n\t\topt.CodecType = DefaultOption.CodecType\n\t}","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-rpc/day4-timeout/client.go#L170-L206","documentation":"Client.Call starts an asynchronous call via Client.Go and then blocks in a select. If the caller-supplied context is cancelled or its deadline expires before the response arrives, Call removes the pending call from the client's pending map and returns this error wrapping ctx.Err(). The library throws it so that context cancellation (timeout or manual cancel) is surfaced as the call result instead of blocking forever.","triggerScenarios":"Calling Call(ctx, ...) where ctx is a context.WithTimeout/WithDeadline that expires before the server replies, or a cancellable context that is cancelled by another goroutine while the RPC is in flight.","commonSituations":"Server handler is slow or hung and the client-side timeout fires; network stall to the server; caller cancels the request context because an upstream HTTP request was aborted; timeout set too aggressively for a heavy method.","solutions":["Increase the context deadline (e.g. context.WithTimeout(ctx, 5*time.Second)) to a value that accommodates the slowest server method","Investigate why the server is slow: profile the handler, check server-side blocking or long DB queries","Handle the timeout explicitly: check errors.Is / strings.HasPrefix against \"rpc client: call failed: context deadline exceeded\" and retry with backoff","Pass context.Background() if the call genuinely has no time limit (use sparingly)"],"exampleFix":"// before\nctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)\ndefer cancel()\nerr := client.Call(ctx, \"Foo.Sum\", req, reply) // times out on slow handlers\n\n// after\nctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)\ndefer cancel()\nerr := client.Call(ctx, \"Foo.Sum\", req, reply)","handlingStrategy":"try-catch","validationCode":"// before calling, ensure the budget is sane\nif deadline, ok := ctx.Deadline(); ok && time.Until(deadline) < 100*time.Millisecond {\n\treturn fmt.Errorf(\"call budget too small: %v\", time.Until(deadline))\n}","typeGuard":null,"tryCatchPattern":"err := client.Call(ctx, \"Foo.Sum\", args, reply)\nif err != nil {\n\tif errors.Is(ctx.Err(), context.DeadlineExceeded) {\n\t\t// timeout path: retry with backoff or fail fast\n\t} else if errors.Is(ctx.Err(), context.Canceled) {\n\t\t// caller cancelled: propagate\n\t}\n}","preventionTips":["Set per-RPC timeouts proportionate to the handler's worst-case latency","Use context.WithTimeoutCause (or wrap) to attach context to timeouts","Add server-side deadlines/metrics to find slow handlers","Retry idempotent calls on deadline exceeded with exponential backoff"],"tags":["rpc","context","timeout","go"],"backgroundTag":"context-deadline-exceeded","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"}