grpc/grpc-go · error

rls: childPolicy config validation failed

Error message

rls: childPolicy config validation failed: %v

What it means

Emitted from parseChildPolicyConfigs (config.go:318) when the child policy's own ConfigParser.ParseConfig rejects the config after the RLS balancer inserted the dummy target field (dummyChildPolicyTarget = "target_name_to_be_filled_in_later"). The child balancer's own validation logic is the source of the rejection; the inner error is wrapped.

Solutions

  1. Read the wrapped %v error from the child balancer; it names the exact failing constraint.
  2. Provide the missing/invalid fields required by the chosen child policy (see that balancer's ParseConfig docs).
  3. Test the child config in isolation by invoking its ParseConfig with the dummy target injected.
  4. If the child policy cannot tolerate the dummy target placeholder (e.g. it strictly validates hostnames), switch to a child policy whose config parser accepts arbitrary target strings.

Example fix

// before: weighted_round_robin missing weightedTargets -> child ParseConfig fails
"childPolicy": [ { "weighted_round_robin": {} } ]

// after: use a simpler child policy that the RLS balancer can validate
"childPolicy": [ { "round_robin": {} } ]
Defensive patterns

Strategy: validation

Validate before calling

// Reproduce the RLS balancer's child-config validation with a dummy target
// so config errors surface before deployment.
func validateChildPolicyConfig(builder balancer.Builder, raw json.RawMessage, targetField string) error {
    parser, ok := builder.(balancer.ConfigParser)
    if !ok {
        return errors.New("child balancer does not implement ConfigParser")
    }
    var m map[string]json.RawMessage
    if err := json.Unmarshal(raw, &m); err != nil {
        return err
    }
    m[targetField], _ = json.Marshal("target_name_to_be_filled_in_later")
    cfg, err := json.Marshal(m)
    if err != nil {
        return err
    }
    if _, err := parser.ParseConfig(cfg); err != nil {
        return fmt.Errorf("child policy rejects config: %w", err)
    }
    return nil
}

Type guard

func childPolicyAcceptsConfig(builder balancer.Builder, raw json.RawMessage, targetField string) bool {
    return validateChildPolicyConfig(builder, raw, targetField) == nil
}

Prevention

When it happens

Trigger: The child policy config is structurally valid JSON but semantically invalid per the child balancer: a required field is missing, a value is out of range, or the target field placeholder is rejected by the child's field validation.

Common situations: weighted_round_robin config missing weightedTargets; a cds/xds child policy used outside an xDS context where it cannot resolve; round_robin/priority config with invalid nested structure; a child policy version that renamed a required field.

Related errors


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

Appendix: 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 0c51461d27)