grpc/grpc-go · error

rls: GrpcKeyBuilder in RouteLookupConfig contains a method…

Error message

rls: GrpcKeyBuilder in RouteLookupConfig contains a method with a slash {%+v}

What it means

A GrpcKeyBuilder.Name.Method must be a bare method name with no slashes, because grpc-go constructs the full path as "/"+Service+"/"+Method (builder.go:93-96). If Method itself contains a '/', the resulting path would be malformed (e.g., "/svc/a/b"), so the builder rejects it up front.

Solutions

  1. Set Name.Method to only the method name without any slash (e.g., "SayHello").
  2. Put the service portion into Name.Service instead.

Example fix

// before
kb.Names = []*rlspb.Name{{Service: "my.pkg.Greeter", Method: "my.pkg.Greeter/SayHello"}}
// after
kb.Names = []*rlspb.Name{{Service: "my.pkg.Greeter", Method: "SayHello"}}
Defensive patterns

Strategy: validation

Validate before calling

func validateMethodNameNoSlash(cfg *rlspb.RouteLookupConfig) error {
	for _, kb := range cfg.GetGrpcKeybuilders() {
		for _, n := range kb.GetNames() {
			if strings.Contains(n.GetMethod(), "/") {
				return fmt.Errorf("Name.Method %q must not contain '/'", n.GetMethod())
			}
		}
	}
	return nil
}

Prevention

When it happens

Trigger: A Name.Method value like "Foo/Bar" or a leading slash. strings.Contains(name.GetMethod(), "/") at builder.go:93 is true.

Common situations: Populating Method with the full path "/service/method" by mistake; copying a method string that already includes the service prefix; config generators that concatenate service + "/" + method into the Method field.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/f5881d9febca5254. Report an issue: GitHub.

Appendix: source

Thrown at balancer/rls/internal/keys/builder.go:94

			constantKeys: constantKeys,
			hostKey:      kb.GetExtraKeys().GetHost(),
			serviceKey:   kb.GetExtraKeys().GetService(),
			methodKey:    kb.GetExtraKeys().GetMethod(),
		}

		// Store the builder created above in the BuilderMap based on the value
		// of the `Names` field, which wraps incoming request's service and
		// method. Also, ensure that there are no repeated `Names` field.
		names := kb.GetNames()
		if len(names) == 0 {
			return nil, fmt.Errorf("rls: GrpcKeyBuilder in RouteLookupConfig does not contain any Name {%+v}", kbs)
		}
		for _, name := range names {
			if name.GetService() == "" {
				return nil, fmt.Errorf("rls: GrpcKeyBuilder in RouteLookupConfig contains a Name field with no Service {%+v}", kbs)
			}
			if strings.Contains(name.GetMethod(), `/`) {
				return nil, fmt.Errorf("rls: GrpcKeyBuilder in RouteLookupConfig contains a method with a slash {%+v}", kbs)
			}
			path := "/" + name.GetService() + "/" + name.GetMethod()
			if _, ok := bm[path]; ok {
				return nil, fmt.Errorf("rls: GrpcKeyBuilder in RouteLookupConfig contains repeated Name field {%+v}", kbs)
			}
			bm[path] = b
		}
	}
	return bm, nil
}

// KeyMap represents the RLS keys to be used for a request.
type KeyMap struct {
	// Map is the representation of an RLS key as a Go map. This is used when
	// an actual RLS request is to be sent out on the wire, since the
	// RouteLookupRequest proto expects a Go map.
	Map map[string]string
	// Str is the representation of an RLS key as a string, sorted by keys.

View on GitHub (pinned to 0c51461d27)