{"record":{"id":"11f78424a86176c9","repo":"grpc/grpc-go","slug":"rls-method-name-q-is-not-of-the-form-service-m","errorCode":null,"errorMessage":"rls: method name %q is not of the form '/service/method","messagePattern":"rls: method name %q is not of the form '/service/method","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"balancer/rls/picker.go","lineNumber":84,"sourceCode":"\tgrpcTarget      string\n\tmetricsRecorder estats.MetricsRecorder\n\tdefaultPolicy   *childPolicyWrapper // Child policy for the default target.\n\tctrlCh          *controlChannel     // Control channel to the RLS server.\n\tmaxAge          time.Duration       // Cache max age from LB config.\n\tstaleAge        time.Duration       // Cache stale age from LB config.\n\tbg              exitIdler\n\tlogger          *internalgrpclog.PrefixLogger\n}\n\n// isFullMethodNameValid return true if name is of the form `/service/method`.\nfunc isFullMethodNameValid(name string) bool {\n\treturn strings.HasPrefix(name, \"/\") && strings.Count(name, \"/\") == 2\n}\n\n// Pick makes the routing decision for every outbound RPC.\nfunc (p *rlsPicker) Pick(info balancer.PickInfo) (balancer.PickResult, error) {\n\tif name := info.FullMethodName; !isFullMethodNameValid(name) {\n\t\treturn balancer.PickResult{}, fmt.Errorf(\"rls: method name %q is not of the form '/service/method\", name)\n\t}\n\n\t// Build the request's keys using the key builders from LB config.\n\tmd, _ := metadata.FromOutgoingContext(info.Ctx)\n\treqKeys := p.kbm.RLSKey(md, p.origEndpoint, info.FullMethodName)\n\n\tp.lb.cacheMu.Lock()\n\tvar pr balancer.PickResult\n\tvar err error\n\n\t// Record metrics without the cache mutex held, to prevent lock contention\n\t// between concurrent RPC's and their Pick calls. Metrics Recording can\n\t// potentially be expensive.\n\tmetricsCallback := func() {}\n\tdefer func() {\n\t\tp.lb.cacheMu.Unlock()\n\t\tmetricsCallback()\n\t}()","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/balancer/rls/picker.go#L66-L102","documentation":"Every gRPC full method name must be of the form \"/<service>/<method>\" (exactly one leading slash and exactly two slashes total). The RLS picker validates this with isFullMethodNameValid (picker.go:77-79) before building the RLS key, because key extraction splits the path on the last '/'. A malformed method name makes RLS routing impossible, so the RPC fails immediately.","triggerScenarios":"A Pick is invoked (an RPC is made) whose FullMethodName lacks the leading '/', has fewer or more than two slashes, or is empty. With generated stubs this is rare; it happens with manual invocations or custom balancer/picker plumbing that sets a bad method name.","commonSituations":"Calling ClientConn.Invoke / InvokeNew with a hand-written method string; a custom interceptor or balancer that overrides FullMethodName; misconfigured generic/unary calls.","solutions":["Ensure the method name passed to Invoke is \"/<fully.qualified.Service>/<Method>\".","Use generated client stubs which always produce correct full method names.","If using generic calls (grpc.NewClient with a manual method), double-check the string has one leading slash and exactly one interior slash."],"exampleFix":"// before\nerr := cc.Invoke(ctx, \"/SayHello\", req, resp) // missing service, only 1 slash\n// after\nerr := cc.Invoke(ctx, \"/my.pkg.Greeter/SayHello\", req, resp)","handlingStrategy":"validation","validationCode":"func isValidFullMethodName(name string) bool {\n\treturn strings.HasPrefix(name, \"/\") && strings.Count(name, \"/\") == 2\n}","typeGuard":null,"tryCatchPattern":"// inside your RPC wrapper\nerr := cc.Invoke(ctx, method, req, resp)\nif err != nil && strings.Contains(err.Error(), \"is not of the form '/service/method\") {\n    // bad method name; fix the caller rather than retry\n    return fmt.Errorf(\"programming error: malformed method %q\", method)\n}","preventionTips":["Use generated client stubs so full method names are always correct.","For manual Invoke, format the method as \"/\" + fullServiceName + \"/\" + methodName.","Add an assertion in test helpers that verifies method names match /^\\/(.+)\\/(.+)$/."],"tags":["go","grpc","rls","rpc","method-name","runtime"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}