{"record":{"id":"56c0ed1225df77c7","repo":"grpc/grpc-go","slug":"outlier-detection-child-balancer-q-not-registere","errorCode":null,"errorMessage":"outlier detection: child balancer %q not registered","messagePattern":"outlier detection: child balancer %q not registered","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/balancer/outlierdetection/balancer.go","lineNumber":298,"sourceCode":"\t\t\tb.unejectEndpoint(epInfo)\n\t\t}\n\t\t// \"Reset each endpoint's ejection time multiplier to 0.\"\n\t\tepInfo.ejectionTimeMultiplier = 0\n\t}\n}\n\nfunc (b *outlierDetectionBalancer) 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\t// Reject whole config if child policy doesn't exist, don't persist it for\n\t// later.\n\tbb := balancer.Get(lbCfg.ChildPolicy.Name)\n\tif bb == nil {\n\t\treturn fmt.Errorf(\"outlier detection: child balancer %q not registered\", lbCfg.ChildPolicy.Name)\n\t}\n\n\t// It is safe to read b.cfg here without holding the mutex, as the only\n\t// write to b.cfg happens later in this function. This function is part of\n\t// the balancer.Balancer API, so it is guaranteed to be called in a\n\t// synchronous manner, so it cannot race with this read.\n\tif b.cfg == nil || b.cfg.ChildPolicy.Name != lbCfg.ChildPolicy.Name {\n\t\tif err := b.child.switchTo(bb); err != nil {\n\t\t\treturn fmt.Errorf(\"outlier detection: error switching to child of type %q: %v\", lbCfg.ChildPolicy.Name, err)\n\t\t}\n\t}\n\n\tb.mu.Lock()\n\t// Inhibit child picker updates until this UpdateClientConnState() call\n\t// completes. If needed, a picker update containing the no-op config bit\n\t// determined from this config and most recent state from the child will be\n\t// sent synchronously upward at the end of this UpdateClientConnState()\n\t// call.","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/balancer/outlierdetection/balancer.go#L280-L316","documentation":"outlier_detection delegates actual load balancing to a child policy. In UpdateClientConnState (balancer.go:296-299) it resolves lbCfg.ChildPolicy.Name via balancer.Get; if no builder is registered, the config is rejected and not persisted, so the previous good config stays active.","triggerScenarios":"lbCfg.ChildPolicy.Name references a balancer name for which no Builder was registered via balancer.Register.","commonSituations":"xDS control plane configures a child policy not compiled into the client; misspelled policy name; stripped gRPC build missing an optional balancer.","solutions":["Add a blank import for the missing balancer package, e.g. `import _ \"google.golang.org/grpc/balancer/roundrobin\"`.","Confirm ChildPolicy.Name matches a registered balancer's Name() exactly.","For custom balancers, ensure init() registers them before any grpc.Dial."],"exampleFix":"// before\nimport _ \"google.golang.org/grpc/balancer/roundrobin\"\n// outlier_detection config sets ChildPolicy.Name = \"weighted_round_robin\"\n// after\nimport (\n    _ \"google.golang.org/grpc/balancer/roundrobin\"\n    _ \"google.golang.org/grpc/balancer/weightedroundrobin\"\n)","handlingStrategy":"validation","validationCode":"func validateOutlierChildPolicyRegistered(name string) error {\n    if balancer.Get(name) == nil {\n        return fmt.Errorf(\"outlier_detection child policy %q is not registered; add a blank import\", name)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Blank-import every child balancer package your xDS deployment may route to.","Cross-check ChildPolicy.Name against balancer.Get at startup.","Document the supported child policy names in your service config schema."],"tags":["go","grpc","xds","balancer","registration","outlier-detection"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}