grpc/grpc-go · error
least-request: lbConfig.choiceCount
Error message
least-request: lbConfig.choiceCount: %v, must be >= 2
What it means
Returned by least_request_experimental's ParseConfig() (balancer/leastrequest/leastrequest.go:73). Per gRFC A48, choiceCount must be >= 2. When unset, the code defaults it to 2 (line 66), so this error only fires when choiceCount is explicitly set to 0 or 1. Values > 10 are silently clamped to 10, but values < 2 are rejected outright.
Solutions
- Set choiceCount to a value between 2 and 10, or omit it entirely to use the default of 2.
- If you want the fewest samples, use exactly 2.
- Add a config validator that rejects choiceCount < 2 before deployment.
Example fix
// before: explicitly sets choiceCount to 1 — rejected
grpc.WithDefaultServiceConfig(`{"loadBalancingConfig":[{"least_request_experimental":{"choiceCount":1}}]}`)
// after: omit choiceCount (defaults to 2) or set it to >= 2
grpc.WithDefaultServiceConfig(`{"loadBalancingConfig":[{"least_request_experimental":{"choiceCount":2}}]}`) Defensive patterns
Strategy: validation
Validate before calling
// Reject choiceCount < 2 before sending the config.
func validateChoiceCount(c uint32) error {
if c < 2 {
return fmt.Errorf("choiceCount %d must be >= 2", c)
}
return nil
} Prevention
- Document that choiceCount is optional and defaults to 2 — do not pass 0 meaning 'default'.
- Add a config schema check (e.g. in an xDS policy validator) for 2 <= choiceCount <= 10.
When it happens
Trigger: The least_request_experimental config JSON explicitly sets choiceCount to 0 or 1, hitting the check at line 72 (lbConfig.ChoiceCount < 2). ParseConfig returns this error, failing service config application.
Common situations: Operator misconfigures choiceCount thinking lower means less overhead; a config template uses 0 meaning 'default' (but 0 is rejected, not defaulted — only omitted is defaulted); xDS control plane pushes an out-of-range value.
Related errors
- least-request: unable to unmarshal LBConfig
- invalid requestHashHeader
- invalid requestHashHeader
- max_ring_size value of
- min_ring_size value of
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/3a86c597811714b4.
Report an issue: GitHub.
Appendix: source
Thrown at balancer/leastrequest/leastrequest.go:73
// ChoiceCount is the number of random SubConns to sample to find the one
// with the fewest outstanding requests. If unset, defaults to 2. If set to
// < 2, the config will be rejected, and if set to > 10, will become 10.
ChoiceCount uint32 `json:"choiceCount,omitempty"`
}
type bb struct{}
func (bb) ParseConfig(s json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {
lbConfig := &LBConfig{
ChoiceCount: 2,
}
if err := json.Unmarshal(s, lbConfig); err != nil {
return nil, fmt.Errorf("least-request: unable to unmarshal LBConfig: %v", err)
}
// "If `choice_count < 2`, the config will be rejected." - A48
if lbConfig.ChoiceCount < 2 { // sweet
return nil, fmt.Errorf("least-request: lbConfig.choiceCount: %v, must be >= 2", lbConfig.ChoiceCount)
}
// "If a LeastRequestLoadBalancingConfig with a choice_count > 10 is
// received, the least_request_experimental policy will set choice_count =
// 10." - A48
if lbConfig.ChoiceCount > 10 {
lbConfig.ChoiceCount = 10
}
return lbConfig, nil
}
func (bb) Name() string {
return Name
}
func (bb) Build(cc balancer.ClientConn, bOpts balancer.BuildOptions) balancer.Balancer {
b := &leastRequestBalancer{
ClientConn: cc,
endpointRPCCounts: resolver.NewEndpointMap[*atomic.Int32](),View on GitHub (pinned to 0c51461d27)