grpc/grpc-go · error

rls: childPolicy config validation failed: %v

Error message

rls: childPolicy config validation failed: %v

What it means

RLS successfully parsed the child policy's config structurally and handed it (with a dummy target injected) to the child policy's own ConfigParser.ParseConfig. That parser returned an error, meaning the child config violates the child policy's rules. The %v is the child policy's own error message.

Source

Thrown at balancer/rls/config.go:318

			return "", nil, fmt.Errorf("rls: childPolicy %q with config %q does not support config parsing", name, string(rawCfg))
		}

		// To validate child policy configs we do the following:
		// - unmarshal the raw JSON bytes of the child policy config into a map
		// - add an entry with key set to `target_field_name` and a dummy value
		// - marshal the map back to JSON and parse the config using the parser
		// retrieved previously
		var childConfig map[string]json.RawMessage
		if err := json.Unmarshal(rawCfg, &childConfig); err != nil {
			return "", nil, fmt.Errorf("rls: json unmarshal failed for child policy config %q: %v", string(rawCfg), err)
		}
		childConfig[targetFieldName], _ = json.Marshal(dummyChildPolicyTarget)
		jsonCfg, err := json.Marshal(childConfig)
		if err != nil {
			return "", nil, fmt.Errorf("rls: json marshal failed for child policy config {%+v}: %v", childConfig, err)
		}
		if _, err := parser.ParseConfig(jsonCfg); err != nil {
			return "", nil, fmt.Errorf("rls: childPolicy config validation failed: %v", err)
		}
		return name, childConfig, nil
	}
	return "", nil, fmt.Errorf("rls: invalid childPolicy config: no supported policies found in %+v", childPolicies)
}

func convertDuration(d *durationpb.Duration) (time.Duration, error) {
	if d == nil {
		return 0, nil
	}
	return d.AsDuration(), d.CheckValid()
}

View on GitHub (pinned to 03255a9237)

Solutions

  1. Read the trailing %v — it is the child policy's specific complaint (e.g. 'wrr: errorUtilizationPenalty must be non-negative').
  2. Correct the offending field per that child policy's documentation.
  3. Confirm the field is supported in your gRPC-Go version before reusing it.

Example fix

// before
"childPolicy": [{ "weighted_round_robin": { "errorUtilizationPenalty": -1 } }]
// after
"childPolicy": [{ "weighted_round_robin": { "errorUtilizationPenalty": 1 } }]
Defensive patterns

Strategy: validation

Validate before calling

func validateChildConfigViaParser(childPolicy []map[string]json.RawMessage, targetField string) error {
    for _, entry := range childPolicy {
        for name, raw := range entry {
            b := balancer.Get(name)
            if b == nil { continue }
            p, ok := b.(balancer.ConfigParser)
            if !ok { continue }
            var m map[string]json.RawMessage
            _ = json.Unmarshal(raw, &m)
            m[targetField], _ = json.Marshal("dummy")
            js, _ := json.Marshal(m)
            if _, err := p.ParseConfig(js); err != nil {
                return fmt.Errorf("child %s config invalid: %w", name, err)
            }
        }
    }
    return nil
}

Prevention

When it happens

Trigger: Passing a syntactically valid but semantically invalid config to the child — e.g. weighted_round_robin with a negative errorUtilizationPenalty, or round_robin with an unknown field when strict parsing is on. The child policy name was accepted but its contents were rejected.

Common situations: Version skew (using a field only supported in a newer gRPC); typo'd field names that look valid; supplying out-of-range numeric values; copying a config example for a different LB policy.

Related errors


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