grpc/grpc-go · error

error parsing loadBalancingConfig for policy

Error message

error parsing loadBalancingConfig for policy %q: %v

What it means

Fires at serviceconfig.go:116 when a registered balancer's ConfigParser.ParseConfig rejects the config JSON supplied for its policy in loadBalancingConfig. The wrapper preserves the policy name and the balancer's own error, so this is the inner balancer (e.g. weighted_round_robin, xds) saying its config block is invalid, not a structural problem with the service config itself.

Solutions

  1. Read the policy name (%q) and the inner %v error to find the exact field the parser rejected.
  2. Consult that balancer's documentation/schema for the expected config fields and correct them.
  3. Confirm the balancer is registered (import its package, e.g. _ "google.golang.org/grpc/balancer/weightedroundrobin") so the parser you expect is the one that ran.
  4. Pin or align client and config-producer versions so the schema matches.

Example fix

// before
// {"loadBalancingConfig": [{"weighted_round_robin": {"children": [{"weight": 10}]}}]}
//   // missing required "target" field on child -> ParseConfig fails

// after
// {"loadBalancingConfig": [{"weighted_round_robin": {"children": [
//   {"target": "cluster_a", "weight": 10}
// ]}}]}
Defensive patterns

Strategy: validation

Validate before calling

// Preflight: ensure every named policy's config parses.
func preflightLBConfig(raw []byte) error {
    var bc svcconfig.BalancerConfig
    if err := json.Unmarshal(raw, &bc); err != nil {
        return err
    }
    return nil
}

Try / catch

var bc svcconfig.BalancerConfig
if err := json.Unmarshal(raw, &bc); err != nil {
    if strings.Contains(err.Error(), "error parsing loadBalancingConfig") {
        // inner balancer rejected its config; check the policy name + inner error
    }
    return err
}

Prevention

When it happens

Trigger: Calling Dial with a service config whose loadBalancingConfig names a registered policy whose config object fails that policy's parser. Examples: weighted_round_robin with a child entry missing the weight field, xds config with an unknown field under strict parsing, or any policy whose JSON doesn't match its expected schema.

Common situations: Upgrading gRPC and a balancer's config schema changed (renamed/required fields); using an xDS-generated config against a client version that expects a different shape; typos in field names within a policy's config block.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/ecb1e3dc29e6028f. Report an issue: GitHub.

Appendix: source

Thrown at internal/serviceconfig/serviceconfig.go:116

		if builder == nil {
			// If the balancer is not registered, move on to the next config.
			// This is not an error.
			continue
		}
		bc.Name = name

		parser, ok := builder.(balancer.ConfigParser)
		if !ok {
			if string(jsonCfg) != "{}" {
				logger.Warningf("non-empty balancer configuration %q, but balancer does not implement ParseConfig", string(jsonCfg))
			}
			// Stop at this, though the builder doesn't support parsing config.
			return nil
		}

		cfg, err := parser.ParseConfig(jsonCfg)
		if err != nil {
			return fmt.Errorf("error parsing loadBalancingConfig for policy %q: %v", name, err)
		}
		bc.Config = cfg
		return nil
	}
	// This is reached when the for loop iterates over all entries, but didn't
	// return. This means we had a loadBalancingConfig slice but did not
	// encounter a registered policy. The config is considered invalid in this
	// case.
	return fmt.Errorf("invalid loadBalancingConfig: no supported policies found in %v", names)
}

// MethodConfig defines the configuration recommended by the service providers for a
// particular method.
type MethodConfig struct {
	// WaitForReady indicates whether RPCs sent to this method should wait until
	// the connection is ready by default (!failfast). The value specified via the
	// gRPC client API will override the value set here.
	WaitForReady *bool

View on GitHub (pinned to 0c51461d27)