grpc/grpc-go · error

rls: GrpcKeyBuilder in RouteLookupConfig contains repeated k

Error message

rls: GrpcKeyBuilder in RouteLookupConfig contains repeated key %q across headers, constant_keys and extra_keys {%+v}

What it means

RLS assembles a single key map per request from three sources — headers, constant_keys, and (implicitly) extra_keys — and the same logical key name must not appear twice or the assembled map would collide. MakeBuilderMap tracks every key in a seenKeys set as it walks constant_keys then headers, and returns this error the moment a header's key is already in the set.

Source

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

	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{
			headerKeys:   matchers,
			constantKeys: constantKeys,
			hostKey:      kb.GetExtraKeys().GetHost(),
			serviceKey:   kb.GetExtraKeys().GetService(),

View on GitHub (pinned to 03255a9237)

Solutions

  1. Give each logical key a unique name across headers and constant_keys (and extra_keys).
  2. If two sources should feed one RLS key, pick one source and drop the other.
  3. Deduplicate with a config lint that collects all keys per builder and asserts uniqueness.

Example fix

// before
"constant_keys": {"env":"prod"},
"headers":   [{"key":"env","names":["x-env"]}]
// after
"constant_keys": {"env":"prod"},
"headers":   [{"key":"region","names":["x-region"]}]
Defensive patterns

Strategy: validation

Validate before calling

func validateUniqueKeys(kb *rlspb.GrpcKeyBuilder) error {
    seen := map[string]bool{}
    for k := range kb.GetConstantKeys() {
        if seen[k] { return fmt.Errorf("dup key %q", k) }
        seen[k] = true
    }
    for _, h := range kb.GetHeaders() {
        k := h.GetKey()
        if seen[k] { return fmt.Errorf("dup key %q across headers/constant_keys", k) }
        seen[k] = true
    }
    return nil
}

Prevention

When it happens

Trigger: A GrpcKeyBuilder where a header's key string equals a constant_keys key, or equals another header's key. E.g. constant_keys {"env":"prod"} plus headers [{"key":"env","names":["x-env"]}].

Common situations: Building key builders incrementally and reusing a key name; merging two builders that each define the same key; intending constant vs. header variants but using one shared key name.

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/83e766f77d402a64. Report an issue: GitHub.