grpc/grpc-go · error
rls: GrpcKeyBuilder in RouteLookupConfig has required_match…
Error message
rls: GrpcKeyBuilder in RouteLookupConfig has required_match field set {%+v} What it means
The RLS (Route Lookup Service) key builder extracts fields from request metadata to form cache keys. Each header matcher in a GrpcKeyBuilder has a `required_match` field, but grpc-go's RLS implementation explicitly rejects any builder whose header sets `required_match=true` (builder.go:55-56). This matches gRFC A24/L12, where required_match is not supported for RLS key builders because all matched headers must always be included. The error is returned from keys.MakeBuilderMap() while the RLS LB policy parses its service config, so the bad config is rejected before any routing happens.
Solutions
- Set required_match to false (or omit it) on every header entry inside each GrpcKeyBuilder in your RouteLookupConfig.
- If the config originates from an xDS control plane, update or reconfigure the control plane so it does not set required_match on RLS key builders.
- Re-test by reloading the service config; the RLS balancer will accept the builder once no header has required_match set.
Example fix
// before (RouteLookupConfig proto)
kb := &rlspb.GrpcKeyBuilder{
Headers: []*rlspb.GrpcKeyBuilder_Name{"key": "region", "required_match": true}},
Names: []*rlspb.GrpcKeyBuilder_Name{{Service: "svc", Method: "Method"}},
}
// after
kb := &rlspb.GrpcKeyBuilder{
Headers: []*rlspb.GrpcKeyBuilder_Header{{Key: "region", Names: []string{"x-region"}}}, // required_match omitted
Names: []*rlspb.GrpcKeyBuilder_Name{{Service: "svc", Method: "Method"}},
} Defensive patterns
Strategy: validation
Validate before calling
func validateRLSKeyBuilders(cfg *rlspb.RouteLookupConfig) error {
for _, kb := range cfg.GetGrpcKeybuilders() {
for _, h := range kb.GetHeaders() {
if h.GetRequiredMatch() {
return fmt.Errorf("header key %q has required_match set; not supported", h.GetKey())
}
}
}
return nil
} Prevention
- Validate the RouteLookupConfig with a helper before applying it as a service config or returning it from a resolver.
- Never copy required_match from Envoy-style RLS configs into gRPC GrpcKeyBuilder protos.
- Add a unit test that feeds your RLS config through keys.MakeBuilderMap and asserts no error.
When it happens
Trigger: An RLS service config is applied (via xDS, WithDefaultServiceConfig, or a service config from the name resolver) whose RouteLookupConfig.grpc_keybuilders[].headers[].required_match is true for at least one header. MakeBuilderMap iterates kb.GetHeaders() and returns this error on the first header with h.GetRequiredMatch()==true.
Common situations: Translating an Envoy RLS config (which supports required_match) into a gRPC client config; an xDS control plane (e.g., older Traffic Director / Istio) emitting required_match on RLS key builders; hand-written RouteLookupConfig protos copied from another data plane.
Related errors
- 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…
- rls: GrpcKeyBuilder in RouteLookupConfig contains a method…
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/c4788f4aca43f45b.
Report an issue: GitHub.
Appendix: source
Thrown at balancer/rls/internal/keys/builder.go:56
kbs := cfg.GetGrpcKeybuilders()
if len(kbs) == 0 {
return nil, errors.New("rls: RouteLookupConfig does not contain any GrpcKeyBuilder")
}
bm := make(map[string]builder)
for _, kb := range kbs {
// Extract keys from `headers`, `constant_keys` and `extra_keys` fields
// and populate appropriate values in the builder struct. Also ensure
// that keys are not repeated.
var matchers []matcher
seenKeys := make(map[string]bool)
constantKeys := kb.GetConstantKeys()
for k := range kb.GetConstantKeys() {
seenKeys[k] = true
}
for _, h := range kb.GetHeaders() {
if h.GetRequiredMatch() {
return nil, fmt.Errorf("rls: GrpcKeyBuilder in RouteLookupConfig has required_match field set {%+v}", kbs)
}
key := h.GetKey()
if seenKeys[key] {
return nil, fmt.Errorf("rls: GrpcKeyBuilder in RouteLookupConfig contains repeated key %q across headers, constant_keys and extra_keys {%+v}", key, kbs)
}
seenKeys[key] = true
matchers = append(matchers, matcher{key: h.GetKey(), names: h.GetNames()})
}
if seenKeys[kb.GetExtraKeys().GetHost()] {
return nil, fmt.Errorf("rls: GrpcKeyBuilder in RouteLookupConfig contains repeated key %q in extra_keys from constant_keys or headers {%+v}", kb.GetExtraKeys().GetHost(), kbs)
}
if seenKeys[kb.GetExtraKeys().GetService()] {
return nil, fmt.Errorf("rls: GrpcKeyBuilder in RouteLookupConfig contains repeated key %q in extra_keys from constant_keys or headers {%+v}", kb.GetExtraKeys().GetService(), kbs)
}
if seenKeys[kb.GetExtraKeys().GetMethod()] {
return nil, fmt.Errorf("rls: GrpcKeyBuilder in RouteLookupConfig contains repeated key %q in extra_keys from constant_keys or headers {%+v}", kb.GetExtraKeys().GetMethod(), kbs)
}
b := builder{View on GitHub (pinned to 0c51461d27)