grpc/grpc-go · error
rls: method name is not of the form '/service/method
Error message
rls: method name %q is not of the form '/service/method
What it means
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.
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.
Example fix
// before err := cc.Invoke(ctx, "/SayHello", req, resp) // missing service, only 1 slash // after err := cc.Invoke(ctx, "/my.pkg.Greeter/SayHello", req, resp)
Defensive patterns
Strategy: validation
Validate before calling
func isValidFullMethodName(name string) bool {
return strings.HasPrefix(name, "/") && strings.Count(name, "/") == 2
} Try / catch
// inside your RPC wrapper
err := cc.Invoke(ctx, method, req, resp)
if err != nil && strings.Contains(err.Error(), "is not of the form '/service/method") {
// bad method name; fix the caller rather than retry
return fmt.Errorf("programming error: malformed method %q", method)
} Prevention
- 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 /^\/(.+)\/(.+)$/.
When it happens
Trigger: 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.
Common situations: Calling ClientConn.Invoke / InvokeNew with a hand-written method string; a custom interceptor or balancer that overrides FullMethodName; misconfigured generic/unary calls.
Related errors
- RLS response's target list does not contain any entries for…
- rls: GrpcKeyBuilder in RouteLookupConfig contains repeated…
- rls: GrpcKeyBuilder in RouteLookupConfig contains a Name…
- rls: GrpcKeyBuilder in RouteLookupConfig contains repeated…
- rls: GrpcKeyBuilder in RouteLookupConfig contains repeated…
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/11f78424a86176c9.
Report an issue: GitHub.
Appendix: source
Thrown at balancer/rls/picker.go:84
grpcTarget string
metricsRecorder estats.MetricsRecorder
defaultPolicy *childPolicyWrapper // Child policy for the default target.
ctrlCh *controlChannel // Control channel to the RLS server.
maxAge time.Duration // Cache max age from LB config.
staleAge time.Duration // Cache stale age from LB config.
bg exitIdler
logger *internalgrpclog.PrefixLogger
}
// isFullMethodNameValid return true if name is of the form `/service/method`.
func isFullMethodNameValid(name string) bool {
return strings.HasPrefix(name, "/") && strings.Count(name, "/") == 2
}
// Pick makes the routing decision for every outbound RPC.
func (p *rlsPicker) Pick(info balancer.PickInfo) (balancer.PickResult, error) {
if name := info.FullMethodName; !isFullMethodNameValid(name) {
return balancer.PickResult{}, fmt.Errorf("rls: method name %q is not of the form '/service/method", name)
}
// Build the request's keys using the key builders from LB config.
md, _ := metadata.FromOutgoingContext(info.Ctx)
reqKeys := p.kbm.RLSKey(md, p.origEndpoint, info.FullMethodName)
p.lb.cacheMu.Lock()
var pr balancer.PickResult
var err error
// Record metrics without the cache mutex held, to prevent lock contention
// between concurrent RPC's and their Pick calls. Metrics Recording can
// potentially be expensive.
metricsCallback := func() {}
defer func() {
p.lb.cacheMu.Unlock()
metricsCallback()
}()View on GitHub (pinned to 0c51461d27)