grpc/grpc-go · error
xds: unable to unmarshal lbconfig: %s, error: %v
Error message
xds: unable to unmarshal lbconfig: %s, error: %v
What it means
The CDS (Cluster Discovery Service) balancer's ParseConfig method attempts to JSON-unmarshal the load balancing config into a struct expecting fields {cluster, isDynamic}. This error fires when the JSON is syntactically invalid or field types are wrong. The CDS balancer is the top-level xDS cluster policy that resolves cluster resources from the management server.
Source
Thrown at internal/xds/balancer/cdsbalancer/cdsbalancer.go:112
// Name returns the name of balancers built by this builder.
func (bb) Name() string {
return cdsName
}
// lbConfig represents the loadBalancingConfig section of the service config
// for the cdsBalancer.
type lbConfig struct {
serviceconfig.LoadBalancingConfig
ClusterName string `json:"cluster"`
IsDynamic bool `json:"isDynamic"`
}
// ParseConfig parses the JSON load balancer config provided into an
// internal form or returns an error if the config is invalid.
func (bb) ParseConfig(c json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {
var cfg lbConfig
if err := json.Unmarshal(c, &cfg); err != nil {
return nil, fmt.Errorf("xds: unable to unmarshal lbconfig: %s, error: %v", string(c), err)
}
return &cfg, nil
}
// cdsBalancer implements a CDS based LB policy. It instantiates a
// cluster_resolver balancer to further resolve the serviceName received from
// CDS, into localities and endpoints. Implements the balancer.Balancer
// interface which is exposed to gRPC and implements the balancer.ClientConn
// interface which is exposed to the cluster_resolver balancer.
type cdsBalancer struct {
// The following fields are initialized at build time and are either
// read-only after that or provide their own synchronization, and therefore
// do not need to be guarded by a mutex.
cc balancer.ClientConn // ClientConn interface passed to child LB.
bOpts balancer.BuildOptions // BuildOptions passed to child LB.
childConfigParser balancer.ConfigParser // Config parser for cluster_resolver LB policy.
logger *grpclog.PrefixLogger // Prefix logger for all logging.
View on GitHub (pinned to 03255a9237)
Solutions
- Inspect the full error message which includes the raw JSON that failed to parse — it will reveal the exact malformed input
- Verify the xDS management server is sending valid JSON with correct field types (cluster as string, isDynamic as boolean)
- Check for version compatibility between your gRPC client and the xDS server protocol version
- Validate that the service config's loadBalancingConfig for cds_experimental matches the expected schema: {"cluster": "<name>", "isDynamic": <bool>}
Example fix
// before: malformed service config with wrong types
{"loadBalancingConfig": [{"cds_experimental": {"cluster": "my_cluster", "isDynamic": "true"}}]}
// after: correct types
{"loadBalancingConfig": [{"cds_experimental": {"cluster": "my_cluster", "isDynamic": true}}]} Defensive patterns
Strategy: validation
Validate before calling
// Validate CDS LB config JSON before passing to xDS
func validateCDSConfig(rawJSON json.RawMessage) error {
var cfg struct {
Cluster string `json:"cluster"`
IsDynamic bool `json:"isDynamic"`
}
if err := json.Unmarshal(rawJSON, &cfg); err != nil {
return fmt.Errorf("invalid CDS config JSON: %w", err)
}
if cfg.Cluster == "" {
return fmt.Errorf("CDS config missing cluster name")
}
return nil
} Type guard
// Type guard for parsed CDS config
func isCDSConfig(cfg serviceconfig.LoadBalancingConfig) bool {
_, ok := cfg.(*cdsbalancer.LBConfig) // or via reflection
return ok
} Prevention
- Validate xDS service config JSON before deploying
- Ensure the management server sends correct types (isDynamic must be boolean, not string)
- Test config changes against the target grpc-go version's ParseConfig schema
- Use xDS integration tests to validate server-emitted configs parse correctly
When it happens
Trigger: Triggered when gRPC's xDS resolver parses the service config's loadBalancingConfig section for the cds_experimental policy and json.Unmarshal fails on the raw JSON. Happens when the xDS server sends a service config with missing required fields, wrong types for cluster/isDynamic, or malformed JSON.
Common situations: Management server (Istio/Envoy/Traffic Director) sends an invalid or incomplete CDS load balancing config; version mismatch between the xDS server and the gRPC client where the server sends new fields the client doesn't understand; bootstrap or service config misconfiguration where the cluster name is empty or isDynamic is a string instead of bool.
Related errors
- failed to correctly update Outlier Detection config %v
- error unmarshalling xDS LB Policy: %v
- error parsing Outlier Detection config %v: %v
- xds: unable to unmarshal LBconfig: %s, error: %v
- no priority is provided, all priorities are removed
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/09116ac3c8155dd8.
Report an issue: GitHub.