{"record":{"id":"2802c591b02927e5","repo":"grpc/grpc-go","slug":"wrr-unable-to-unmarshal-lb-policy-config-s-err","errorCode":null,"errorMessage":"wrr: unable to unmarshal LB policy config: %s, error: %v","messagePattern":"wrr: unable to unmarshal LB policy config: (.+?), error: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"balancer/weightedroundrobin/balancer.go","lineNumber":130,"sourceCode":"\tb.child = endpointsharding.NewBalancer(b, bOpts, balancer.Get(pickfirst.Name).Build, endpointsharding.Options{})\n\tb.logger = prefixLogger(b)\n\tif b.logger.V(2) {\n\t\tb.logger.Infof(\"Created\")\n\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","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/balancer/weightedroundrobin/balancer.go#L112-L148","documentation":"The weighted_round_robin balancer's ParseConfig json.Unmarshal's the incoming LB config into its lbConfig struct (with A58 defaults pre-filled). If the JSON is malformed or contains fields whose types do not match the struct, the unmarshal fails and this error — including the raw config and the json error — is returned to the resolver/gRPC core, which then rejects the service config.","triggerScenarios":"A weighted_round_robin config that is not valid JSON or has wrong-typed fields — e.g. \"blackoutPeriod\": \"abc\" (string instead of duration), a trailing comma, or an unexpected top-level type.","commonSituations":"Hand-editing the WRR service config; mixing up field names/types with another LB policy; tooling that emits non-strict JSON; version skew where a field was renamed.","solutions":["Validate the config JSON with jq and against the A58 spec fields (enableOobLoadReport, oobReportingPeriod, blackoutPeriod, weightExpirationPeriod, weightUpdatePeriod, errorUtilizationPenalty).","Use Go duration strings (e.g. \"10s\") for all *_period fields and a number for errorUtilizationPenalty.","Generate the config with encoding/json rather than templating strings."],"exampleFix":"// before\n[{ \"weighted_round_robin\": { \"blackoutPeriod\": \"abc\", \"errorUtilizationPenalty\": \"1\" } }]\n// after\n[{ \"weighted_round_robin\": { \"blackoutPeriod\": \"10s\", \"errorUtilizationPenalty\": 1 } }]","handlingStrategy":"validation","validationCode":"func validateWRRConfig(js json.RawMessage) error {\n    cfg := &lbConfig{} // weightedroundrobin.lbConfig with A58 defaults\n    if err := json.Unmarshal(js, cfg); err != nil {\n        return fmt.Errorf(\"invalid wrr config JSON: %w\", err)\n    }\n    if cfg.ErrorUtilizationPenalty < 0 {\n        return fmt.Errorf(\"errorUtilizationPenalty must be non-negative\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate the WRR config with jq before deploying.","Use Go duration strings for all *_period fields and a number for errorUtilizationPenalty.","Generate configs programmatically with encoding/json."],"tags":["wrr","service-config","config-validation","go","grpc","load-balancing"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}