{"record":{"id":"17d54ce39a9b9b26","repo":"grpc/grpc-go","slug":"child-policy-q-not-registered","errorCode":null,"errorMessage":"child policy %q not registered","messagePattern":"child policy %q not registered","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/balancer/clusterimpl/clusterimpl.go","lineNumber":412,"sourceCode":"\tdefer clientConnUpdateHook()\n\n\tb.mu.Lock()\n\tb.inhibitPickerUpdates = true\n\tb.mu.Unlock()\n\tif b.logger.V(2) {\n\t\tb.logger.Infof(\"Received configuration: %s\", pretty.ToJSON(s.BalancerConfig))\n\t}\n\tnewConfig, ok := s.BalancerConfig.(*LBConfig)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected balancer config with type: %T\", s.BalancerConfig)\n\t}\n\n\t// Need to check for potential errors at the beginning of this function, so\n\t// that on errors, we reject the whole config, instead of applying part of\n\t// it.\n\tbb := balancer.Get(newConfig.ChildPolicy.Name)\n\tif bb == nil {\n\t\treturn fmt.Errorf(\"child policy %q not registered\", newConfig.ChildPolicy.Name)\n\t}\n\n\tif b.xdsClient == nil {\n\t\tc := xdsclient.FromResolverState(s.ResolverState)\n\t\tif c == nil {\n\t\t\treturn balancer.ErrBadResolverState\n\t\t}\n\t\tb.xdsClient = c\n\t}\n\n\txdsConfig := xdsresource.XDSConfigFromResolverState(s.ResolverState)\n\tif xdsConfig == nil {\n\t\tb.logger.Warningf(\"Received balancer config with no xDS config\")\n\t\treturn balancer.ErrBadResolverState\n\t}\n\tclusterCfg := xdsConfig.Clusters[newConfig.Cluster]\n\tclusterUpdate := clusterCfg.Config.Cluster\n\tif err := b.handleSecurityConfig(clusterUpdate.SecurityCfg); err != nil {","sourceCodeStart":394,"sourceCodeEnd":430,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/balancer/clusterimpl/clusterimpl.go#L394-L430","documentation":"In UpdateClientConnState (clusterimpl.go:410-412), cluster_impl resolves its child policy name via balancer.Get; if no builder was registered for that name, the entire config is rejected. The child policy is the actual load-distribution algorithm (round_robin, ring_hash, weighted_round_robin, least_request) that cluster_impl delegates endpoint selection to.","triggerScenarios":"newConfig.ChildPolicy.Name references a balancer name (e.g. \"ring_hash_experimental\", \"least_request_experimental\") for which no Builder was registered via balancer.Register at process start.","commonSituations":"xDS control plane configures a policy (RING_HASH, LEAST_REQUEST) that the client binary does not link in; misspelled policy name in the xDS Cluster resource; client built with a stripped gRPC that omits optional balancer plugins.","solutions":["Add a blank import for the missing balancer package, e.g. `import _ \"google.golang.org/grpc/balancer/ringhash\"`.","Confirm the ChildPolicy.Name string in the xDS Cluster resource exactly matches a registered balancer's Name().","For custom balancers, ensure init() calls balancer.Register before any grpc.Dial."],"exampleFix":"// before\nimport _ \"google.golang.org/grpc/balancer/roundrobin\"\n// xDS Cluster resource requests policy: RING_HASH -> error\n// after\nimport (\n    _ \"google.golang.org/grpc/balancer/roundrobin\"\n    _ \"google.golang.org/grpc/balancer/ringhash\"\n)","handlingStrategy":"validation","validationCode":"// Before sending config, ensure the child policy is registered.\nfunc validateChildPolicyRegistered(name string) error {\n    if balancer.Get(name) == nil {\n        return fmt.Errorf(\"child policy %q is not registered; add a blank import for its package\", name)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Blank-import every balancer package your xDS deployment may reference (roundrobin, ringhash, weightedroundrobin, leastrequest, etc.).","Cross-check ChildPolicy.Name against balancer.Get at startup in a sanity test.","Document the set of supported policy names in your service config."],"tags":["go","grpc","xds","balancer","registration","clusterimpl"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}