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 = scView on GitHub (pinned to 03255a9237)
Solutions
- Read the %v json error (it gives line/offset) and fix the JSON at that point.
- Run the config through a JSON validator before applying it.
- Ensure routeLookupConfig is a JSON object (protojson form) and childPolicy is an array of policy objects.
- 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
- Validate RLS service config JSON in CI before deploying.
- Generate the config from typed structs and marshal, rather than hand-writing strings.
- Diff against a known-good RLS config when debugging.
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
- randomsubsetting: json.Unmarshal failed for configuration: %
- rls: bad RouteLookupConfig proto %+v: %v
- rls: bad control channel service config %q: %v
- rls: childPolicyConfigTargetFieldName field is not set in se
- rls: empty lookup_service in route lookup config %+v
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/5ae15a295950568e.
Report an issue: GitHub.