{"record":{"id":"83e766f77d402a64","repo":"grpc/grpc-go","slug":"rls-grpckeybuilder-in-routelookupconfig-contains","errorCode":null,"errorMessage":"rls: GrpcKeyBuilder in RouteLookupConfig contains repeated key %q across headers, constant_keys and extra_keys {%+v}","messagePattern":"rls: GrpcKeyBuilder in RouteLookupConfig contains repeated key %q across headers, constant_keys and extra_keys (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"balancer/rls/internal/keys/builder.go","lineNumber":60,"sourceCode":"\n\tbm := make(map[string]builder)\n\tfor _, kb := range kbs {\n\t\t// Extract keys from `headers`, `constant_keys` and `extra_keys` fields\n\t\t// and populate appropriate values in the builder struct. Also ensure\n\t\t// that keys are not repeated.\n\t\tvar matchers []matcher\n\t\tseenKeys := make(map[string]bool)\n\t\tconstantKeys := kb.GetConstantKeys()\n\t\tfor k := range kb.GetConstantKeys() {\n\t\t\tseenKeys[k] = true\n\t\t}\n\t\tfor _, h := range kb.GetHeaders() {\n\t\t\tif h.GetRequiredMatch() {\n\t\t\t\treturn nil, fmt.Errorf(\"rls: GrpcKeyBuilder in RouteLookupConfig has required_match field set {%+v}\", kbs)\n\t\t\t}\n\t\t\tkey := h.GetKey()\n\t\t\tif seenKeys[key] {\n\t\t\t\treturn nil, fmt.Errorf(\"rls: GrpcKeyBuilder in RouteLookupConfig contains repeated key %q across headers, constant_keys and extra_keys {%+v}\", key, kbs)\n\t\t\t}\n\t\t\tseenKeys[key] = true\n\t\t\tmatchers = append(matchers, matcher{key: h.GetKey(), names: h.GetNames()})\n\t\t}\n\t\tif seenKeys[kb.GetExtraKeys().GetHost()] {\n\t\t\treturn nil, fmt.Errorf(\"rls: GrpcKeyBuilder in RouteLookupConfig contains repeated key %q in extra_keys from constant_keys or headers {%+v}\", kb.GetExtraKeys().GetHost(), kbs)\n\t\t}\n\t\tif seenKeys[kb.GetExtraKeys().GetService()] {\n\t\t\treturn nil, fmt.Errorf(\"rls: GrpcKeyBuilder in RouteLookupConfig contains repeated key %q in extra_keys from constant_keys or headers {%+v}\", kb.GetExtraKeys().GetService(), kbs)\n\t\t}\n\t\tif seenKeys[kb.GetExtraKeys().GetMethod()] {\n\t\t\treturn nil, fmt.Errorf(\"rls: GrpcKeyBuilder in RouteLookupConfig contains repeated key %q in extra_keys from constant_keys or headers {%+v}\", kb.GetExtraKeys().GetMethod(), kbs)\n\t\t}\n\t\tb := builder{\n\t\t\theaderKeys:   matchers,\n\t\t\tconstantKeys: constantKeys,\n\t\t\thostKey:      kb.GetExtraKeys().GetHost(),\n\t\t\tserviceKey:   kb.GetExtraKeys().GetService(),","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/balancer/rls/internal/keys/builder.go#L42-L78","documentation":"When building the RLS key map, grpc-go collects every key name from constant_keys, headers, and extra_keys into a single set and forbids duplicates (builder.go:49-63). If a header's key string equals a key already present in constant_keys (or another header), MakeBuilderMap returns this error. Each RLS key field must map to a uniquely named key in the outgoing RouteLookupRequest.","triggerScenarios":"A GrpcKeyBuilder declares a constant_keys entry with key \"zone\" and also a header with key \"zone\"; or two headers share the same key. The seenKeys map (seeded from constant_keys, then from each header) detects the collision at builder.go:59.","commonSituations":"Renaming a key in one place but not the other when editing an RLS config; merging two key builders together; an xDS-sourced config where constant_keys and header keys were authored independently.","solutions":["Inspect the reported duplicate key name and search the GrpcKeyBuilder's constant_keys, headers, and extra_keys for all occurrences.","Rename one of the colliding entries so every key name is unique within a single GrpcKeyBuilder.","If the duplication is intentional (two sources feeding one key), collapse them into a single header matcher with multiple Names."],"exampleFix":"// before\nkb := &rlspb.GrpcKeyBuilder{\n  ConstantKeys: map[string]string{\"region\": \"us\"},\n  Headers:      []*rlspb.Header{{Key: \"region\", Names: []string{\"x-region\"}}},\n}\n// after\nkb := &rlspb.GrpcKeyBuilder{\n  ConstantKeys: map[string]string{\"region\": \"us\"},\n  Headers:      []*rlspb.Header{{Key: \"zone\", Names: []string{\"x-zone\"}}}, // renamed\n}","handlingStrategy":"validation","validationCode":"func validateUniqueKeys(cfg *rlspb.RouteLookupConfig) error {\n\tfor _, kb := range cfg.GetGrpcKeybuilders() {\n\t\tseen := map[string]bool{}\n\t\tfor k := range kb.GetConstantKeys() {\n\t\t\tif seen[k] { return fmt.Errorf(\"dup constant key %q\", k) }\n\t\t\tseen[k] = true\n\t\t}\n\t\tfor _, h := range kb.GetHeaders() {\n\t\t\tk := h.GetKey()\n\t\t\tif seen[k] { return fmt.Errorf(\"repeated key %q across constant/headers\", k) }\n\t\t\tseen[k] = true\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat key names as unique identifiers within a GrpcKeyBuilder; namespace them if unsure (host_, svc_, method_).","Generate RLS configs from a single source of truth so renames propagate everywhere.","Run keys.MakeBuilderMap on your config in tests to catch duplicates before deploy."],"tags":["go","grpc","rls","config","validation","balancer"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}