{"record":{"id":"d48f695305c7d713","repo":"grpc/grpc-go","slug":"xds-wrr-locality-missing-locality-weight-informat","errorCode":null,"errorMessage":"xds_wrr_locality: missing locality weight information in endpoint %q","messagePattern":"xds_wrr_locality: missing locality weight information in endpoint %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/balancer/wrrlocality/balancer.go","lineNumber":170,"sourceCode":"}\n\nfunc (b *wrrLocalityBalancer) UpdateClientConnState(s balancer.ClientConnState) error {\n\tlbCfg, ok := s.BalancerConfig.(*LBConfig)\n\tif !ok {\n\t\tb.logger.Errorf(\"Received config with unexpected type %T: %v\", s.BalancerConfig, s.BalancerConfig)\n\t\treturn balancer.ErrBadResolverState\n\t}\n\n\tweightedTargets := make(map[string]weightedtarget.Target)\n\tfor _, ep := range s.ResolverState.Endpoints {\n\t\t// This get of LocalityID could potentially return a zero value. This\n\t\t// shouldn't happen though (this attribute that is set actually gets\n\t\t// used to build localities in the first place), and thus don't error\n\t\t// out, and just build a weighted target with undefined behavior.\n\t\tlocality := xdsinternal.LocalityString(xdsinternal.LocalityIDFromEndpoint(ep))\n\t\tai, ok := getAddrInfo(ep)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"xds_wrr_locality: missing locality weight information in endpoint %q\", ep)\n\t\t}\n\t\tweightedTargets[locality] = weightedtarget.Target{Weight: ai.LocalityWeight, ChildPolicy: lbCfg.ChildPolicy}\n\t}\n\twtCfg := &weightedtarget.LBConfig{Targets: weightedTargets}\n\twtCfgJSON, err := json.Marshal(wtCfg)\n\tif err != nil {\n\t\t// Shouldn't happen.\n\t\treturn fmt.Errorf(\"xds_wrr_locality: error marshalling prepared config: %v\", wtCfg)\n\t}\n\tvar sc serviceconfig.LoadBalancingConfig\n\tif sc, err = b.childParser.ParseConfig(wtCfgJSON); err != nil {\n\t\treturn fmt.Errorf(\"xds_wrr_locality: config generated %v is invalid: %v\", wtCfgJSON, err)\n\t}\n\n\treturn b.child.UpdateClientConnState(balancer.ClientConnState{\n\t\tResolverState:  s.ResolverState,\n\t\tBalancerConfig: sc,\n\t})","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/xds/balancer/wrrlocality/balancer.go#L152-L188","documentation":"Returned by wrr_locality UpdateClientConnState (internal/xds/balancer/wrrlocality/balancer.go:170) when an endpoint in the resolver state has no AddrInfo attribute (no locality weight). The xDS resolver normally attaches AddrInfo with the locality weight to every endpoint; wrr_locality needs it to build weighted targets per locality.","triggerScenarios":"UpdateClientConnState iterates endpoints and getAddrInfo(ep) returns ok=false for one of them, meaning the resolver did not call SetAddrInfo to attach a LocalityWeight attribute. This should not happen in the real xDS flow; it indicates the resolver state was not produced by the xDS resolver.","commonSituations":"A non-xDS resolver feeds endpoints into a channel using the wrr_locality policy; the xDS resolver was bypassed or a custom resolver omitted the locality weight attribute; a partially-mocked resolver in tests.","solutions":["Ensure the channel is driven by the xDS resolver so endpoints carry AddrInfo","If building endpoints manually, attach the weight via wrrlocality.SetAddrInfo(ep, AddrInfo{LocalityWeight: w})","Use wrr_locality only within the xDS-managed path"],"exampleFix":"// before: endpoint built without locality weight\nep := resolver.Endpoint{...}\n// after\nimport \"google.golang.org/grpc/internal/xds/balancer/wrrlocality\"\nep := wrrlocality.SetAddrInfo(resolver.Endpoint{...}, wrrlocality.AddrInfo{LocalityWeight: 100})","handlingStrategy":"validation","validationCode":"// Ensure every endpoint carries a locality weight before UpdateClientConnState.\nfor _, ep := range state.ResolverState.Endpoints {\n    if _, ok := wrrlocality.GetAddrInfoPublic(ep); !ok {\n        return fmt.Errorf(\"endpoint missing locality weight; not from xDS resolver\")\n    }\n}","typeGuard":"func endpointsHaveLocalityWeight(eps []resolver.Endpoint) bool {\n    for _, ep := range eps {\n        v := ep.Attributes.Value(attributeKey{})\n        if _, ok := v.(wrrlocality.AddrInfo); !ok {\n            return false\n        }\n    }\n    return true\n}","tryCatchPattern":"if err := bal.UpdateClientConnState(state); err != nil {\n    if strings.Contains(err.Error(), \"missing locality weight\") {\n        logger.Errorf(\"endpoints not produced by xDS resolver; skip wrr_locality: %v\", err)\n    }\n    return err\n}","preventionTips":["Use wrr_locality only behind the xDS resolver","When constructing endpoints manually, call wrrlocality.SetAddrInfo","In tests, always attach AddrInfo to fake endpoints"],"tags":["grpc","xds","wrr-locality","load-balancing","resolver","go"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}