{"record":{"id":"82a9469e07d62437","repo":"grpc/grpc-go","slug":"xds-wrr-locality-invalid-lbconfig-s-error-v","errorCode":null,"errorMessage":"xds_wrr_locality: invalid LBConfig: %s, error: %v","messagePattern":"xds_wrr_locality: invalid LBConfig: (.+?), error: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/balancer/wrrlocality/balancer.go","lineNumber":95,"sourceCode":"\twtbCfgParser, ok := builder.(balancer.ConfigParser)\n\tif !ok {\n\t\t// Shouldn't happen, imported weighted target builder has this method.\n\t\treturn nil\n\t}\n\twrrL := &wrrLocalityBalancer{\n\t\tchild:       wtb,\n\t\tchildParser: wtbCfgParser,\n\t}\n\n\twrrL.logger = prefixLogger(wrrL)\n\twrrL.logger.Infof(\"Created\")\n\treturn wrrL\n}\n\nfunc (bb) ParseConfig(s json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {\n\tvar lbCfg *LBConfig\n\tif err := json.Unmarshal(s, &lbCfg); err != nil {\n\t\treturn nil, fmt.Errorf(\"xds_wrr_locality: invalid LBConfig: %s, error: %v\", string(s), err)\n\t}\n\tif lbCfg == nil || lbCfg.ChildPolicy == nil {\n\t\treturn nil, errors.New(\"xds_wrr_locality: invalid LBConfig: child policy field must be set\")\n\t}\n\treturn lbCfg, nil\n}\n\ntype attributeKey struct{}\n\n// Equal allows the values to be compared by Attributes.Equal.\nfunc (a AddrInfo) Equal(o any) bool {\n\toa, ok := o.(AddrInfo)\n\treturn ok && oa.LocalityWeight == a.LocalityWeight\n}\n\n// AddrInfo is the locality weight of the locality an address is a part of.\ntype AddrInfo struct {\n\tLocalityWeight uint32","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/balancer/wrrlocality/balancer.go#L77-L113","documentation":"Thrown by the xDS wrr_locality (weighted round-robin locality) custom LB balancer when ParseConfig cannot json.Unmarshal its service config. The config is expected to be a JSON object containing a 'childPolicy' field (per gRFC A52). If the raw JSON handed to the balancer is malformed or the wrong shape, unmarshalling fails here.","triggerScenarios":"Called when the gRPC core invokes bb.ParseConfig(s json.RawMessage) at balancer.go:92 with a value that fails json.Unmarshal into *LBConfig. This is driven by the xDS resolver translating a service config whose xds_wrr_locality_experimental LB config block is not valid JSON or lacks the expected struct shape.","commonSituations":"xDS control plane pushes a malformed wrr_locality config block; service config version skew between server and client; manually constructing a service config JSON that omits the object wrapper or passes a non-object value for childPolicy.","solutions":["Inspect the full error string: it embeds the offending raw JSON (the %s). Compare it against the LBConfig struct {childPolicy} shape.","Validate the wrr_locality config block in your LDS/CDS response or service config is a JSON object with a childPolicy field before publishing.","Confirm gRPC client and xDS server support the same xDS custom LB policy version (A52).","If you are unit-testing this balancer directly, ensure you pass json.RawMessage of a valid JSON object, e.g. {\"childPolicy\":[{\"round_robin\":{}}]}."],"exampleFix":"// before (bad raw config passed to balancer)\ncfg := json.RawMessage(`not-json`)\nparsed, err := bb.ParseConfig(cfg) // returns error 380\n\n// after\ncfg := json.RawMessage(`{\"childPolicy\":[{\"round_robin\":{}}]}`)\nparsed, err := bb.ParseConfig(cfg)","handlingStrategy":"validation","validationCode":"// Validate an xds_wrr_locality LB config block before handing it to the balancer.\nfunc validateWRRLocalityConfig(raw json.RawMessage) error {\n    var cfg struct {\n        ChildPolicy json.RawMessage `json:\"childPolicy\"`\n    }\n    if err := json.Unmarshal(raw, &cfg); err != nil {\n        return fmt.Errorf(\"wrr_locality config is not valid JSON: %w\", err)\n    }\n    if len(cfg.ChildPolicy) == 0 {\n        return fmt.Errorf(\"wrr_locality config missing childPolicy\")\n    }\n    return nil\n}","typeGuard":"// Narrow a parsed service config to the wrr_locality LBConfig type.\nfunc isWRRLocalityLBConfig(cfg serviceconfig.LoadBalancingConfig) (*wrrlocality.LBConfig, bool) {\n    lb, ok := cfg.(*wrrlocality.LBConfig)\n    return lb, ok && lb != nil && lb.ChildPolicy != nil\n}","tryCatchPattern":"// ParseConfig returns an error, not a panic. Handle it at the resolver/config layer.\nparsed, err := bb.ParseConfig(raw)\nif err != nil {\n    return fmt.Errorf(\"reject service config, bad wrr_locality block: %w\", err)\n}","preventionTips":["Always wrap childPolicy in a JSON object before passing to ParseConfig.","Unit-test balancer ParseConfig with representative configs from your control plane.","Log the raw JSON on parse failure (the error already includes it) to speed up diagnosis."],"tags":["grpc","xds","balancer","wrr-locality","config","go"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}