grpc/grpc-go · error
least-request: unable to unmarshal LBConfig
Error message
least-request: unable to unmarshal LBConfig: %v
What it means
Returned by least_request_experimental's ParseConfig() (balancer/leastrequest/leastrequest.go:69) when json.Unmarshal of the raw LB config into LBConfig fails. The %v is the underlying json error. LBConfig expects an optional numeric 'choiceCount' field; any JSON syntax error or type mismatch triggers this. The error propagates up through the service config parser and prevents the channel from applying the policy.
Solutions
- Validate the JSON config string with a JSON linter before applying it.
- Ensure choiceCount (if present) is a JSON number, not a string.
- Check the embedded json error (%v) for the exact field and reason.
- If the config comes from xDS, inspect the LDS/CDS resource the control plane sent.
Example fix
// before: choiceCount as a string — invalid JSON unmarshal
grpc.WithDefaultServiceConfig(`{"loadBalancingConfig":[{"least_request_experimental":{"choiceCount":"2"}}]}`)
// after: choiceCount as a number (or omitted to default to 2)
grpc.WithDefaultServiceConfig(`{"loadBalancingConfig":[{"least_request_experimental":{"choiceCount":2}}]}`) Defensive patterns
Strategy: validation
Validate before calling
// Validate the least_request config JSON before applying it.
func validateLeastRequestConfig(js string) error {
var cfg struct {
ChoiceCount uint32 `json:"choiceCount,omitempty"`
}
if err := json.Unmarshal([]byte(js), &cfg); err != nil {
return fmt.Errorf("invalid least_request config JSON: %w", err)
}
return nil
} Prevention
- Lint service config JSON in CI before deployment.
- Use json.Valid on config strings sourced from user input or xDS.
- Unit-test ParseConfig with representative config samples.
When it happens
Trigger: The service config / xDS LB policy config for least_request_experimental contains malformed JSON or a wrong type for choiceCount (e.g. a string or object). ParseConfig() is invoked by the channel when parsing the loadBalancingConfig entry, and json.Unmarshal returns a non-nil error.
Common situations: A typo in the JSON service config (trailing comma, unquoted key); choiceCount passed as a string "2" instead of number 2; a malformed config pushed by an xDS control plane; hand-written service config string with invalid JSON.
Related errors
- least-request: lbConfig.choiceCount
- pickfirst: unable to unmarshal LB policy config
- randomsubsetting: json.Unmarshal failed for configuration
- expected a JSON struct with one entry; received entry
- invalid requestHashHeader
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/a5929bce946a67fc.
Report an issue: GitHub.
Appendix: source
Thrown at balancer/leastrequest/leastrequest.go:69
// LBConfig is the balancer config for least_request_experimental balancer.
type LBConfig struct {
serviceconfig.LoadBalancingConfig `json:"-"`
// 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
}
View on GitHub (pinned to 0c51461d27)