{"record":{"id":"e021edf7b970a72e","repo":"grpc/grpc-go","slug":"rls-grpckeybuilder-in-routelookupconfig-contains-e021ed","errorCode":null,"errorMessage":"rls: GrpcKeyBuilder in RouteLookupConfig contains repeated Name field {%+v}","messagePattern":"rls: GrpcKeyBuilder in RouteLookupConfig contains repeated Name field (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"balancer/rls/internal/keys/builder.go","lineNumber":98,"sourceCode":"\t\t}\n\n\t\t// Store the builder created above in the BuilderMap based on the value\n\t\t// of the `Names` field, which wraps incoming request's service and\n\t\t// method. Also, ensure that there are no repeated `Names` field.\n\t\tnames := kb.GetNames()\n\t\tif len(names) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"rls: GrpcKeyBuilder in RouteLookupConfig does not contain any Name {%+v}\", kbs)\n\t\t}\n\t\tfor _, name := range names {\n\t\t\tif name.GetService() == \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"rls: GrpcKeyBuilder in RouteLookupConfig contains a Name field with no Service {%+v}\", kbs)\n\t\t\t}\n\t\t\tif strings.Contains(name.GetMethod(), `/`) {\n\t\t\t\treturn nil, fmt.Errorf(\"rls: GrpcKeyBuilder in RouteLookupConfig contains a method with a slash {%+v}\", kbs)\n\t\t\t}\n\t\t\tpath := \"/\" + name.GetService() + \"/\" + name.GetMethod()\n\t\t\tif _, ok := bm[path]; ok {\n\t\t\t\treturn nil, fmt.Errorf(\"rls: GrpcKeyBuilder in RouteLookupConfig contains repeated Name field {%+v}\", kbs)\n\t\t\t}\n\t\t\tbm[path] = b\n\t\t}\n\t}\n\treturn bm, nil\n}\n\n// KeyMap represents the RLS keys to be used for a request.\ntype KeyMap struct {\n\t// Map is the representation of an RLS key as a Go map. This is used when\n\t// an actual RLS request is to be sent out on the wire, since the\n\t// RouteLookupRequest proto expects a Go map.\n\tMap map[string]string\n\t// Str is the representation of an RLS key as a string, sorted by keys.\n\t// Since the RLS keys are part of the cache key in the request cache\n\t// maintained by the RLS balancer, and Go maps cannot be used as keys for\n\t// Go maps (the cache is implemented as a map), we need a stringified\n\t// version of it.","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/balancer/rls/internal/keys/builder.go#L80-L116","documentation":"BuilderMap is keyed by the /service/method path. As MakeBuilderMap walks every Name of every builder, it inserts each computed path into the map and rejects a second insertion of an already-present path. This catches both duplicates within one builder and overlaps across builders (e.g. one builder matching the whole service and another matching a method of it where both resolve to the same path).","triggerScenarios":"Two Names that compute to the same path — e.g. one builder with names [{service:\"S\", method:\"M\"}] and another also listing {service:\"S\", method:\"M\"}; or a builder whose whole-service Name (method \"\") collides with a method-specific Name resolving to an identical path edge case.","commonSituations":"Appending builders from multiple config sources; merging per-team key builders that touch the same RPC; overriding one builder with another without removing the original.","solutions":["Ensure each /service/method path appears in exactly one Name across all builders.","Consolidate duplicate Names into a single builder, merging their headers/constant_keys (without reusing keys).","Run a pre-deploy lint that collects all computed paths and asserts uniqueness."],"exampleFix":"// before\n// builder A: names=[{S,M}]  builder B: names=[{S,M}]\n// after\n// single builder: names=[{S,M}] headers/constant_keys merged","handlingStrategy":"validation","validationCode":"func validateUniquePaths(cfg *rlspb.RouteLookupConfig) error {\n    seen := map[string]int{}\n    for _, kb := range cfg.GetGrpcKeybuilders() {\n        for _, n := range kb.GetNames() {\n            path := \"/\" + n.GetService() + \"/\" + n.GetMethod()\n            if _, ok := seen[path]; ok {\n                return fmt.Errorf(\"duplicate path %q across Names\", path)\n            }\n            seen[path] = 1\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Deduplicate Names across builders before publishing the config.","Merge colliding builders into one, combining their headers/constant_keys (with unique keys).","Add a path-uniqueness lint to config CI."],"tags":["rls","service-config","config-validation","go","grpc","key-builder"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}