grpc/grpc-go · error

failed to parse load balancing policy for child %q: %v

Error message

failed to parse load balancing policy for child %q: %v

What it means

The cluster manager parses the JSON-marshaled child policy config using the gracefulswitch balancer's ParseConfig. This error fires when the JSON is not valid for gracefulswitch's expected format, which wraps a single child policy in a specific JSON array structure. This is distinct from a marshal failure — the JSON was produced but doesn't parse correctly in the target format.

Source

Thrown at internal/xds/balancer/clustermanager/clustermanager.go:129

			// child fail, while RPCs to other children with good configs
			// continue to succeed.
			newPolicyName, oldPolicyName := childCfg.ChildPolicy.Name, b.children[childName].ChildPolicy.Name
			if newPolicyName != oldPolicyName {
				var err error
				var cfgJSON []byte
				cfgJSON, err = childCfg.ChildPolicy.MarshalJSON()
				if err != nil {
					retErr = fmt.Errorf("failed to JSON marshal load balancing policy for child %q: %v", childName, err)
					b.setErrorPickerForChild(childName, retErr)
					continue
				}
				// This overwrites lbCfg to be in the format expected by the
				// gracefulswitch balancer. So, when this config is pushed to
				// the child (below), it will result in a graceful switch to the
				// new child policy.
				lbCfg, err = balancergroup.ParseConfig(cfgJSON)
				if err != nil {
					retErr = fmt.Errorf("failed to parse load balancing policy for child %q: %v", childName, err)
					b.setErrorPickerForChild(childName, retErr)
					continue
				}
			}
		}

		if err := b.bg.UpdateClientConnState(childName, balancer.ClientConnState{
			ResolverState: resolver.State{
				Endpoints:     endpointsSplit[childName],
				ServiceConfig: s.ResolverState.ServiceConfig,
				Attributes:    s.ResolverState.Attributes,
			},
			BalancerConfig: lbCfg,
		}); err != nil {
			retErr = fmt.Errorf("failed to push new configuration %v to child %q: %v", childCfg.ChildPolicy.Config, childName, err)
			b.setErrorPickerForChild(childName, retErr)
		}

View on GitHub (pinned to 03255a9237)

Solutions

  1. Verify you are on a consistent grpc-go version across all imports (check go.mod for version mismatches)
  2. Enable GRPC_GO_LOG_SEVERITY=info to see which child and what JSON caused the parse failure
  3. If using custom balancers, ensure their JSON output conforms to the gracefulswitch config format
  4. Upgrade grpc-go — this is likely a version compatibility issue or regression
  5. The error is isolated to the affected child; other children continue operating
Defensive patterns

Strategy: validation

Validate before calling

// Validate that marshaled child policy JSON can be parsed by gracefulswitch
// (relevant for testing; normally xDS handles this internally)
func validateGracefulswitchParse(cfgJSON []byte) error {
    _, err := gracefulswitch.ParseConfig(cfgJSON)
    return err
}

Try / catch

// This error is isolated to one child; other children continue working
// The affected child's RPCs will fail while others succeed

Prevention

When it happens

Trigger: Triggered in cluster_manager's UpdateClientConnState when balancergroup.ParseConfig(cfgJSON) fails. cfgJSON was just produced by MarshalJSON on the child policy config, so this indicates the marshaled output doesn't conform to the gracefulswitch parser's expected schema. This typically indicates a version mismatch or a bug in the child policy's MarshalJSON producing incompatible output.

Common situations: A grpc-go version where the child policy's MarshalJSON and gracefulswitch's ParseConfig have incompatible expectations; a custom child balancer with a non-standard MarshalJSON; the child policy config struct references types not understood by the gracefulswitch parser; a regression in the balancergroup parser.

Understand the failure class

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/23f76a9165f9786d. Report an issue: GitHub.