{"record":{"id":"89dcb33e87721437","repo":"grpc/grpc-go","slug":"unexpected-balancer-config-with-type-t","errorCode":null,"errorMessage":"unexpected balancer config with type: %T","messagePattern":"unexpected balancer config with type: %T","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/balancer/clusterimpl/clusterimpl.go","lineNumber":404,"sourceCode":"\toldHI := b.xdsHIPtr.Swap(newHI)\n\tif oldHI != nil {\n\t\toldHI.Decrement()\n\t}\n\treturn nil\n}\n\nfunc (b *clusterImplBalancer) UpdateClientConnState(s balancer.ClientConnState) error {\n\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","sourceCodeStart":386,"sourceCodeEnd":422,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/xds/balancer/clusterimpl/clusterimpl.go#L386-L422","documentation":"The cluster_impl balancer's UpdateClientConnState expects BalancerConfig to be of type *LBConfig (the cluster_impl-specific config struct). This error fires when the config has a different type, indicating a misconfiguration in how the balancer tree was assembled. The config should always be *LBConfig when the CDS/priority balancer properly routes to cluster_impl.","triggerScenarios":"Triggered at the start of cluster_impl's UpdateClientConnState when the type assertion s.BalancerConfig.(*LBConfig) fails. This means the resolver or parent balancer passed a config of an unexpected type (e.g., a raw map, a different balancer's config struct, or nil).","commonSituations":"A misconfigured xDS balancer chain where the wrong config type is routed to cluster_impl; a bug in the parent priority or CDS balancer that constructs the wrong config type; manual or programmatic construction of balancer.ClientConnState with incorrect config types; a version mismatch where LBConfig struct layout changed between packages.","solutions":["This error indicates an internal gRPC configuration error — the balancer tree assembly is broken. Report as a bug with the grpc-go version and xDS configuration","Verify you are not manually constructing balancer configs for the xDS balancer chain","Ensure no custom balancer intercepts or replaces the config passed to cluster_impl","Upgrade grpc-go to a stable release, as this may be a regression","Enable GRPC_GO_LOG_SEVERITY=info to see what config type was actually received"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"// Verify the config type matches before calling UpdateClientConnState\n// (applicable if constructing balancer configs programmatically)\nfunc isClusterImplConfig(cfg serviceconfig.LoadBalancingConfig) bool {\n    _, ok := cfg.(*clusterimpl.LBConfig)\n    return ok\n}","typeGuard":"// Type guard for cluster_impl config\nfunc isClusterImplLBConfig(v interface{}) bool {\n    _, ok := v.(*clusterimpl.LBConfig)\n    return ok\n}","tryCatchPattern":null,"preventionTips":["Do not manually construct balancer configs for the xDS balancer chain","Use standard xDS balancer setup via grpc.NewClient with xds resolver","Keep grpc-go versions consistent across all imports","Report unexpected config type errors as bugs"],"tags":["xds","clusterimpl","type-assertion","config","internal"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}