{"record":{"id":"60011aacd3cc7bf4","repo":"grpc/grpc-go","slug":"wrr-errorutilizationpenalty-must-be-non-negative","errorCode":null,"errorMessage":"wrr: errorUtilizationPenalty must be non-negative","messagePattern":"wrr: errorUtilizationPenalty must be non-negative","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"balancer/weightedroundrobin/balancer.go","lineNumber":134,"sourceCode":"\t}\n\treturn b\n}\n\nfunc (bb) ParseConfig(js json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {\n\tlbCfg := &lbConfig{\n\t\t// Default values as documented in A58.\n\t\tOOBReportingPeriod:      iserviceconfig.Duration(10 * time.Second),\n\t\tBlackoutPeriod:          iserviceconfig.Duration(10 * time.Second),\n\t\tWeightExpirationPeriod:  iserviceconfig.Duration(3 * time.Minute),\n\t\tWeightUpdatePeriod:      iserviceconfig.Duration(time.Second),\n\t\tErrorUtilizationPenalty: 1,\n\t}\n\tif err := json.Unmarshal(js, lbCfg); err != nil {\n\t\treturn nil, fmt.Errorf(\"wrr: unable to unmarshal LB policy config: %s, error: %v\", string(js), err)\n\t}\n\n\tif lbCfg.ErrorUtilizationPenalty < 0 {\n\t\treturn nil, fmt.Errorf(\"wrr: errorUtilizationPenalty must be non-negative\")\n\t}\n\n\t// For easier comparisons later, ensure the OOB reporting period is unset\n\t// (0s) when OOB reports are disabled.\n\tif !lbCfg.EnableOOBLoadReport {\n\t\tlbCfg.OOBReportingPeriod = 0\n\t}\n\n\t// Impose lower bound of 100ms on weightUpdatePeriod.\n\tif !internal.AllowAnyWeightUpdatePeriod && lbCfg.WeightUpdatePeriod < iserviceconfig.Duration(100*time.Millisecond) {\n\t\tlbCfg.WeightUpdatePeriod = iserviceconfig.Duration(100 * time.Millisecond)\n\t}\n\n\treturn lbCfg, nil\n}\n\nfunc (bb) Name() string {\n\treturn Name","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/balancer/weightedroundrobin/balancer.go#L116-L152","documentation":"The weighted_round_robin (WRR) load balancer validates its service config inside ParseConfig (balancer.go:133). errorUtilizationPenalty is a float64 that scales how much an endpoint's weight is reduced for its error rate (weight = rps/(utilization + errorRate*penalty)). A negative value is rejected because it would make error-prone endpoints appear MORE attractive, inverting the load-balancing intent. The default is 1.0.","triggerScenarios":"Setting \"errorUtilizationPenalty\" to a negative number in the JSON config for the weighted_round_robin LB policy — via a service config file, xDS control plane, or the WithDefaultServiceConfig / defaultServiceConfigRawJSON dial option. ParseConfig calls json.Unmarshal then checks lbCfg.ErrorUtilizationPenalty < 0.","commonSituations":"A hand-written service config JSON with a stray minus sign or typo; an xDS management server pushing an out-of-range value; copy-pasting an OOB reporting template and editing the penalty incorrectly.","solutions":["Set errorUtilizationPenalty to 0 or a positive number (e.g. 1.0) in the service config JSON, or omit the field to use the default 1.0.","If the config comes from xDS, fix the value at the control plane / management server and re-push.","Validate the LB config JSON with a schema or a dry-run parse before applying it to a live channel."],"exampleFix":"// before\n{\"loadBalancingConfig\":{\"weighted_round_robin\":{\"errorUtilizationPenalty\":-0.5}}}\n// after\n{\"loadBalancingConfig\":{\"weighted_round_robin\":{\"errorUtilizationPenalty\":1.0}}}","handlingStrategy":"validation","validationCode":"// Validate before applying service config JSON for weighted_round_robin.\nfunc validateWRRCfg(js []byte) error {\n    cfg := struct{ ErrorUtilizationPenalty *float64 `json:\"errorUtilizationPenalty\"` }{}\n    if err := json.Unmarshal(js, &cfg); err != nil { return err }\n    if cfg.ErrorUtilizationPenalty != nil && *cfg.ErrorUtilizationPenalty < 0 {\n        return fmt.Errorf(\"errorUtilizationPenalty must be >= 0, got %v\", *cfg.ErrorUtilizationPenalty)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat errorUtilizationPenalty as an unsigned scaling factor; never compute it from a subtraction that can go negative.","Run the service config JSON through your schema/validator before pushing to xDS or WithDefaultServiceConfig.","Unit-test ParseConfig-equivalent validation against boundary values (0, negative, large)."],"tags":["go","grpc","load-balancing","config","validation"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}