grpc/grpc-go · error

rls: childPolicyConfigTargetFieldName field is not set in…

Error message

rls: childPolicyConfigTargetFieldName field is not set in service config %+v

What it means

Emitted from (rlsBB).ParseConfig (config.go:174) when ChildPolicyConfigTargetFieldName is the empty string. The RLS balancer injects each RLS-resolved target into the child policy config under this field name (e.g. round_robin uses 'serviceName'), so it is mandatory.

Solutions

  1. Add childPolicyConfigTargetFieldName to the RLS config object with the field name the chosen child policy expects for its target.
  2. For round_robin children use 'round_robin' -> target field 'serviceName'; for pick_first use 'serviceName' as well; confirm against the child policy's config struct.
  3. If the config is xDS-sourced, fix the RouteLookupClusterSpecification on the control plane to include childPolicyConfigTargetFieldName.

Example fix

// before
{ "rls": { "routeLookupConfig": { ... }, "childPolicy": [ { "round_robin": {} } ] } }

// after
{ "rls": {
    "routeLookupConfig": { ... },
    "childPolicyConfigTargetFieldName": "serviceName",
    "childPolicy": [ { "round_robin": {} } ]
} }
Defensive patterns

Strategy: validation

Validate before calling

func validateChildTargetField(name string) error {
    if strings.TrimSpace(name) == "" {
        return errors.New("childPolicyConfigTargetFieldName must be set and non-empty")
    }
    return nil
}

Type guard

func hasChildTargetField(name string) bool { return strings.TrimSpace(name) != "" }

Prevention

When it happens

Trigger: The top-level JSON config has no childPolicyConfigTargetFieldName key, or its value is an empty string. The check runs after the RouteLookupConfig proto is parsed but before child-policy validation.

Common situations: A config template that omits the field; an xDS RLS plugin that was not populated with the target field name; copying an example config that used a different schema version where the field was implicit.

Related errors


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

Appendix: source

Thrown at balancer/rls/config.go:174

	rlsProto := &rlspb.RouteLookupConfig{}
	if err := m.Unmarshal(cfgJSON.RouteLookupConfig, rlsProto); err != nil {
		return nil, fmt.Errorf("rls: bad RouteLookupConfig proto %+v: %v", string(cfgJSON.RouteLookupConfig), err)
	}
	lbCfg, err := parseRLSProto(rlsProto)
	if err != nil {
		return nil, err
	}

	if sc := string(cfgJSON.RouteLookupChannelServiceConfig); sc != "" {
		parsed := internal.ParseServiceConfig.(func(string) *serviceconfig.ParseResult)(sc)
		if parsed.Err != nil {
			return nil, fmt.Errorf("rls: bad control channel service config %q: %v", sc, parsed.Err)
		}
		lbCfg.controlChannelServiceConfig = sc
	}

	if cfgJSON.ChildPolicyConfigTargetFieldName == "" {
		return nil, fmt.Errorf("rls: childPolicyConfigTargetFieldName field is not set in service config %+v", string(c))
	}
	name, config, err := parseChildPolicyConfigs(cfgJSON.ChildPolicy, cfgJSON.ChildPolicyConfigTargetFieldName)
	if err != nil {
		return nil, err
	}
	lbCfg.childPolicyName = name
	lbCfg.childPolicyConfig = config
	lbCfg.childPolicyTargetField = cfgJSON.ChildPolicyConfigTargetFieldName
	return lbCfg, nil
}

func parseRLSProto(rlsProto *rlspb.RouteLookupConfig) (*lbConfig, error) {
	// Validations specified on the `grpc_keybuilders` field are performed here.
	kbMap, err := keys.MakeBuilderMap(rlsProto)
	if err != nil {
		return nil, err
	}

View on GitHub (pinned to 0c51461d27)