grpc/grpc-go · error

rls: GrpcKeyBuilder in RouteLookupConfig contains repeated N

Error message

rls: GrpcKeyBuilder in RouteLookupConfig contains repeated Name field {%+v}

What it means

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).

Source

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

		}

		// 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.
	// Since the RLS keys are part of the cache key in the request cache
	// maintained by the RLS balancer, and Go maps cannot be used as keys for
	// Go maps (the cache is implemented as a map), we need a stringified
	// version of it.

View on GitHub (pinned to 03255a9237)

Solutions

  1. Ensure each /service/method path appears in exactly one Name across all builders.
  2. Consolidate duplicate Names into a single builder, merging their headers/constant_keys (without reusing keys).
  3. Run a pre-deploy lint that collects all computed paths and asserts uniqueness.

Example fix

// before
// builder A: names=[{S,M}]  builder B: names=[{S,M}]
// after
// single builder: names=[{S,M}] headers/constant_keys merged
Defensive patterns

Strategy: validation

Validate before calling

func validateUniquePaths(cfg *rlspb.RouteLookupConfig) error {
    seen := map[string]int{}
    for _, kb := range cfg.GetGrpcKeybuilders() {
        for _, n := range kb.GetNames() {
            path := "/" + n.GetService() + "/" + n.GetMethod()
            if _, ok := seen[path]; ok {
                return fmt.Errorf("duplicate path %q across Names", path)
            }
            seen[path] = 1
        }
    }
    return nil
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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