grpc/grpc-go · error

rls: json unmarshal failed for service config %+v: %v

Error message

rls: json unmarshal failed for service config %+v: %v

What it means

Returned by rls.ParseConfig (config.go:150-153) when json.Unmarshal of the RLS service config into lbConfigJSON fails. lbConfigJSON has four raw fields (RouteLookupConfig, RouteLookupChannelServiceConfig, ChildPolicy, ChildPolicyConfigTargetFieldName); the top-level JSON must be a well-formed object containing these. The %+v is the raw JSON string and %v the json error.

Source

Thrown at balancer/rls/config.go:152

//	   - `cache_size_bytes` field must have a value greater than 0, and if its
//	     value is greater than 5M, we cap it at 5M
//
//	- routeLookupChannelServiceConfig:
//	  - if specified, must parse as valid service config
//
//	- childPolicy:
//	  - must find a valid child policy with a valid config
//
//	- childPolicyConfigTargetFieldName:
//	  - must be set and non-empty
func (rlsBB) ParseConfig(c json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {
	if logger.V(2) {
		logger.Infof("Received JSON service config: %v", pretty.ToJSON(c))
	}

	cfgJSON := &lbConfigJSON{}
	if err := json.Unmarshal(c, cfgJSON); err != nil {
		return nil, fmt.Errorf("rls: json unmarshal failed for service config %+v: %v", string(c), err)
	}

	m := protojson.UnmarshalOptions{DiscardUnknown: true}
	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

View on GitHub (pinned to 03255a9237)

Solutions

  1. Read the %v json error (it gives line/offset) and fix the JSON at that point.
  2. Run the config through a JSON validator before applying it.
  3. Ensure routeLookupConfig is a JSON object (protojson form) and childPolicy is an array of policy objects.
  4. If from xDS, inspect the RLS Cluster config the control plane produced.

Example fix

// before
raw := `{ "routeLookupConfig": {...}, "childPolicy": [...] }` // syntax error somewhere

// after: validate with encoding/json; ensure valid object with the four expected fields
Defensive patterns

Strategy: validation

Validate before calling

func validateRLSJSON(raw []byte) error {
    var c struct {
        RouteLookupConfig                json.RawMessage `json:"routeLookupConfig"`
        ChildPolicyConfigTargetFieldName string          `json:"childPolicyConfigTargetFieldName"`
    }
    if err := json.Unmarshal(raw, &c); err != nil {
        return fmt.Errorf("rls JSON invalid: %w", err)
    }
    return nil
}

Prevention

When it happens

Trigger: The RLS service config string is syntactically invalid JSON, or a field that must be an object/array is the wrong JSON type, causing unmarshal to fail before any proto parsing.

Common situations: Hand-authoring the RLS service config JSON and introducing a syntax error. Control plane emitting a malformed RLS config. Version skew where a new/required field changed type.

Related errors


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