{"record":{"id":"09116ac3c8155dd8","repo":"grpc/grpc-go","slug":"xds-unable-to-unmarshal-lbconfig-s-error-v","errorCode":null,"errorMessage":"xds: unable to unmarshal lbconfig: %s, error: %v","messagePattern":"xds: unable to unmarshal lbconfig: (.+?), error: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/balancer/cdsbalancer/cdsbalancer.go","lineNumber":112,"sourceCode":"// Name returns the name of balancers built by this builder.\nfunc (bb) Name() string {\n\treturn cdsName\n}\n\n// lbConfig represents the loadBalancingConfig section of the service config\n// for the cdsBalancer.\ntype lbConfig struct {\n\tserviceconfig.LoadBalancingConfig\n\tClusterName string `json:\"cluster\"`\n\tIsDynamic   bool   `json:\"isDynamic\"`\n}\n\n// ParseConfig parses the JSON load balancer config provided into an\n// internal form or returns an error if the config is invalid.\nfunc (bb) ParseConfig(c json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {\n\tvar cfg lbConfig\n\tif err := json.Unmarshal(c, &cfg); err != nil {\n\t\treturn nil, fmt.Errorf(\"xds: unable to unmarshal lbconfig: %s, error: %v\", string(c), err)\n\t}\n\treturn &cfg, nil\n}\n\n// cdsBalancer implements a CDS based LB policy. It instantiates a\n// cluster_resolver balancer to further resolve the serviceName received from\n// CDS, into localities and endpoints. Implements the balancer.Balancer\n// interface which is exposed to gRPC and implements the balancer.ClientConn\n// interface which is exposed to the cluster_resolver balancer.\ntype cdsBalancer struct {\n\t// The following fields are initialized at build time and are either\n\t// read-only after that or provide their own synchronization, and therefore\n\t// do not need to be guarded by a mutex.\n\tcc                balancer.ClientConn   // ClientConn interface passed to child LB.\n\tbOpts             balancer.BuildOptions // BuildOptions passed to child LB.\n\tchildConfigParser balancer.ConfigParser // Config parser for cluster_resolver LB policy.\n\tlogger            *grpclog.PrefixLogger // Prefix logger for all logging.\n","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/xds/balancer/cdsbalancer/cdsbalancer.go#L94-L130","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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>}"],"exampleFix":"// before: malformed service config with wrong types\n{\"loadBalancingConfig\": [{\"cds_experimental\": {\"cluster\": \"my_cluster\", \"isDynamic\": \"true\"}}]}\n// after: correct types\n{\"loadBalancingConfig\": [{\"cds_experimental\": {\"cluster\": \"my_cluster\", \"isDynamic\": true}}]}","handlingStrategy":"validation","validationCode":"// Validate CDS LB config JSON before passing to xDS\nfunc validateCDSConfig(rawJSON json.RawMessage) error {\n    var cfg struct {\n        Cluster  string `json:\"cluster\"`\n        IsDynamic bool  `json:\"isDynamic\"`\n    }\n    if err := json.Unmarshal(rawJSON, &cfg); err != nil {\n        return fmt.Errorf(\"invalid CDS config JSON: %w\", err)\n    }\n    if cfg.Cluster == \"\" {\n        return fmt.Errorf(\"CDS config missing cluster name\")\n    }\n    return nil\n}","typeGuard":"// Type guard for parsed CDS config\nfunc isCDSConfig(cfg serviceconfig.LoadBalancingConfig) bool {\n    _, ok := cfg.(*cdsbalancer.LBConfig) // or via reflection\n    return ok\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["xds","cds","json","config","balancer"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}