grpc/grpc-go · error
unexpected balancer config with type: %T
Error message
unexpected balancer config with type: %T
What it means
Returned by xds_cluster_impl's UpdateClientConnState when s.BalancerConfig cannot be type-asserted to *clusterimpl.LBConfig (clusterimpl.go:402-404). The cluster_impl policy only accepts its own strongly-typed config carrying the cluster name, drop categories, security cfg, and child policy. Any other type means the upstream resolver/balancer produced the wrong shape and the whole update is rejected.
Source
Thrown at internal/xds/balancer/clusterimpl/clusterimpl.go:404
oldHI := b.xdsHIPtr.Swap(newHI)
if oldHI != nil {
oldHI.Decrement()
}
return nil
}
func (b *clusterImplBalancer) UpdateClientConnState(s balancer.ClientConnState) error {
defer clientConnUpdateHook()
b.mu.Lock()
b.inhibitPickerUpdates = true
b.mu.Unlock()
if b.logger.V(2) {
b.logger.Infof("Received configuration: %s", pretty.ToJSON(s.BalancerConfig))
}
newConfig, ok := s.BalancerConfig.(*LBConfig)
if !ok {
return fmt.Errorf("unexpected balancer config with type: %T", s.BalancerConfig)
}
// Need to check for potential errors at the beginning of this function, so
// that on errors, we reject the whole config, instead of applying part of
// it.
bb := balancer.Get(newConfig.ChildPolicy.Name)
if bb == nil {
return fmt.Errorf("child policy %q not registered", newConfig.ChildPolicy.Name)
}
if b.xdsClient == nil {
c := xdsclient.FromResolverState(s.ResolverState)
if c == nil {
return balancer.ErrBadResolverState
}
b.xdsClient = c
}
View on GitHub (pinned to 0c51461d27)
Solutions
- Route the config through clusterimpl.ParseConfig(rawJSON) and pass the returned *LBConfig as BalancerConfig.
- If writing a custom parent balancer, never wrap or translate the config into a different type before calling UpdateClientConnState.
- Verify resolver and balancer plugin come from the same gRPC-go version.
Example fix
// before
b.UpdateClientConnState(balancer.ClientConnState{
BalancerConfig: &SomeOtherConfig{}, // wrong type
})
// after
import "google.golang.org/grpc/internal/xds/balancer/clusterimpl"
cfg, err := clusterimpl.ParseConfig(rawJSON)
if err != nil { return err }
b.UpdateClientConnState(balancer.ClientConnState{
BalancerConfig: cfg, // *clusterimpl.LBConfig
}) Defensive patterns
Strategy: type-guard
Validate before calling
// Before invoking UpdateClientConnState, ensure the config is *clusterimpl.LBConfig.
func validateClusterImplConfig(cfg serviceconfig.LoadBalancingConfig) error {
if _, ok := cfg.(*clusterimpl.LBConfig); !ok {
return fmt.Errorf("expected *clusterimpl.LBConfig, got %T", cfg)
}
return nil
} Type guard
func isClusterImplConfig(cfg serviceconfig.LoadBalancingConfig) bool {
_, ok := cfg.(*clusterimpl.LBConfig)
return ok
} Prevention
- Always produce the config via clusterimpl.ParseConfig rather than constructing it manually.
- Do not wrap or translate the LBConfig into a different type between resolver and balancer.
- Pin resolver and balancer packages to the same gRPC-go version.
When it happens
Trigger: UpdateClientConnState is invoked on a cluster_impl balancer with s.BalancerConfig of any type other than *clusterimpl.LBConfig (e.g. *clustermanager.lbConfig, *priority.LBConfig, a raw struct, or nil where the assertion expects non-nil).
Common situations: A custom parent balancer that bypasses clusterimpl.ParseConfig and hands down a different struct; gRPC-go version drift where the LBConfig struct layout changed between the resolver and the balancer plugin; tests that construct ClientConnState manually with the wrong config type.
Related errors
- child policy %q not registered
- unexpected balancer config with type: %T
- unexpected balancer config with type: %T
- last resolver error: %v
- received Cluster resource that contains invalid security con
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/89dcb33e87721437.
Report an issue: GitHub.