{"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/03255a9237b6eb32710f6bc4f2de9a675b99fe36/balancer/rls/picker.go#L66-L102","documentation":"At the start of every Pick, rlsPicker verifies the RPC's FullMethodName matches the gRPC convention /service/method (one leading slash and exactly two slashes total via isFullMethodNameValid). If not, it refuses to route because the key-builder lookup (which splits on the last slash) would produce garbage keys. This is a runtime error returned from the picker, not a config error.","triggerScenarios":"Calling a gRPC method whose FullMethodName is not of the form /service/method — e.g. \"Get\", \"service/method\" (missing leading slash), or \"/a/b/c\" (three slashes). Typically only seen with custom invocation handlers, in-process servers with malformed method registration, or proxying tooling that fabricates method names.","commonSituations":"Using grpc.NewServer with a service whose method name was registered oddly; hand-built streaming proxies; test harnesses that invoke Pick directly with an arbitrary string; custom resolver/interceptor rewriting FullMethodName.","solutions":["Ensure the RPC is invoked through a normally-generated gRPC client stub so FullMethodName is /package.Service/Method.","If proxying, normalize the method to /service/method before it reaches the picker.","Check for interceptors/transformers that strip or mangle the leading slash."],"exampleFix":"// before: invoking with a malformed method\nconn.NewConn().Invoke(ctx, \"Get\", req, resp)\n// after: use the generated stub (method name is /pkg.Svc/Get)\nclient := pb.NewSvcClient(conn)\nclient.Get(ctx, req)","handlingStrategy":"try-catch","validationCode":"func isValidFullMethodName(name string) bool {\n    return strings.HasPrefix(name, \"/\") && strings.Count(name, \"/\") == 2\n}","typeGuard":null,"tryCatchPattern":"err := conn.Invoke(ctx, method, req, resp)\nif err != nil && strings.Contains(err.Error(), \"is not of the form '/service/method\") {\n    // method name is malformed; re-route through a generated stub or normalize method\n    log.Printf(\"malformed method name %q; falling back\", method)\n}","preventionTips":["Always call RPCs through generated client stubs so FullMethodName is well-formed.","If proxying, normalize the method to /service/method before invoking.","Watch for interceptors that strip the leading slash from FullMethodName."],"tags":["rls","runtime","picker","go","grpc","method-name"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}