grpc/grpc-go · error
rls: bad RouteLookupConfig proto %+v: %v
Error message
rls: bad RouteLookupConfig proto %+v: %v
What it means
Returned by rls.ParseConfig (config.go:155-159) when the routeLookupConfig bytes cannot be unmarshalled via protojson into rlspb.RouteLookupConfig (with DiscardUnknown=true). This means the JSON is valid JSON but does not match the RouteLookupConfig proto schema (wrong field names, bad nested structure, invalid enum/Duration encoding). The %+v is the raw routeLookupConfig string.
Source
Thrown at balancer/rls/config.go:158
// - 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
}
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)View on GitHub (pinned to 03255a9237)
Solutions
- Compare the routeLookupConfig JSON against the grpc.lookup.v1.RouteLookupConfig proto definition; fix mismatched field names/types.
- For google.protobuf.Duration fields use the "Ns" or seconds+nanos JSON form protojson expects.
- Regenerate the config from a known-good RouteLookupConfig proto instance (protojson.Marshal) and diff.
- Check the xDS control plane's RLS proto version against the client's.
Example fix
// before: routeLookupConfig with wrong duration encoding or bad field name
rlc := `{ "lookupService": "rls.example", "grpcKeybuilders": [...], "maxAge": "5m" }` // 'maxAge' wrong shape
// after: build it from a typed proto and marshal
b, _ := protojson.Marshal(&rlspb.RouteLookupConfig{ LookupService: "rls.example", MaxAge: durationpb.New(5*time.Minute) }) Defensive patterns
Strategy: validation
Validate before calling
import "google.golang.org/protobuf/encoding/protojson"
import rlsproto "...grpc_lookup_v1"
func validateRouteLookupConfig(raw []byte) error {
var p rlsproto.RouteLookupConfig
return protojson.UnmarshalOptions{DiscardUnknown: true}.Unmarshal(raw, &p)
} Prevention
- Build routeLookupConfig from a typed RouteLookupConfig proto and marshal with protojson.
- Use canonical protojson Duration/enum encodings.
- Keep the client's RLS proto version in sync with the control plane.
When it happens
Trigger: routeLookupConfig is valid JSON but uses field names that are not in grpc.lookup.v1.RouteLookupConfig, or encodes a duration/enum in a non-canonical way that protojson rejects.
Common situations: Control plane translating RLS config with a stale or wrong proto. Hand-writing the proto JSON with camelCase vs snake_case confusion (protojson accepts both, but typos are rejected). Including unknown fields (allowed due to DiscardUnknown, so this is usually a real schema mismatch).
Related errors
- rls: failed to parse lookup_service_timeout in route lookup
- rls: failed to parse max_age in route lookup config %+v: %v
- rls: failed to parse staleAge in route lookup config %+v: %v
- rls: json unmarshal failed for service config %+v: %v
- rls: bad control channel service config %q: %v
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/16315a81aa37a37d.
Report an issue: GitHub.