grpc/grpc-go · error

rls_csp: error parsing config

Error message

rls_csp: error parsing config %v: %v

What it means

The Any-wrapped configuration could not be unmarshaled into a RouteLookupClusterSpecifier proto (rls.go:64-65). The serialized bytes in the Any message do not match the grpc.lookup.v1.RouteLookupClusterSpecifier schema, or the TypeURL is incorrect.

Solutions

  1. Verify the TypeURL in the Any matches 'type.googleapis.com/grpc.lookup.v1.RouteLookupClusterSpecifier'
  2. Ensure the xDS server and gRPC client use compatible RLS proto versions
  3. Check xDS transport logs for payload corruption indicators
  4. Use an xDS config dump to inspect the raw Any payload bytes and TypeURL
Defensive patterns

Strategy: validation

Validate before calling

// Validate the TypeURL before attempting to unmarshal.
const rlsTypeURL = "type.googleapis.com/grpc.lookup.v1.RouteLookupClusterSpecifier"
if anyMsg.TypeUrl != rlsTypeURL {
    return fmt.Errorf("unexpected TypeURL %q, want %q", anyMsg.TypeUrl, rlsTypeURL)
}

Try / catch

result, err := plugin.ParseClusterSpecifierConfig(anyCfg)
if err != nil && strings.Contains(err.Error(), "error parsing config") {
    log.Printf("RLS config unmarshal failed — likely TypeURL or proto version mismatch: %v", err)
}

Prevention

When it happens

Trigger: anypb.Any.UnmarshalTo(rlcs) fails because the Any payload is corrupted, truncated, or the TypeURL does not match 'type.googleapis.com/grpc.lookup.v1.RouteLookupClusterSpecifier'.

Common situations: xDS server proto version mismatch (server uses a newer or older RLS proto revision); TypeURL in the Any does not match the expected RLS type URL; network-level payload corruption; xDS server sends a different proto type under the RLS type URL.

Related errors


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

Appendix: source

Thrown at internal/xds/clusterspecifier/rls/rls.go:65

// configuration, and the other fields will be hardcoded.
type lbConfigJSON struct {
	RouteLookupConfig                json.RawMessage              `json:"routeLookupConfig"`
	ChildPolicy                      []map[string]json.RawMessage `json:"childPolicy"`
	ChildPolicyConfigTargetFieldName string                       `json:"childPolicyConfigTargetFieldName"`
}

func (rls) ParseClusterSpecifierConfig(cfg proto.Message) (clusterspecifier.BalancerConfig, error) {
	if cfg == nil {
		return nil, fmt.Errorf("rls_csp: nil configuration message provided")
	}
	m, ok := cfg.(*anypb.Any)
	if !ok {
		return nil, fmt.Errorf("rls_csp: error parsing config %v: unknown type %T", cfg, cfg)
	}
	rlcs := new(rlspb.RouteLookupClusterSpecifier)

	if err := m.UnmarshalTo(rlcs); err != nil {
		return nil, fmt.Errorf("rls_csp: error parsing config %v: %v", cfg, err)
	}
	rlcJSON, err := protojson.Marshal(rlcs.GetRouteLookupConfig())
	if err != nil {
		return nil, fmt.Errorf("rls_csp: error marshaling route lookup config: %v: %v", rlcs.GetRouteLookupConfig(), err)
	}
	lbCfgJSON := &lbConfigJSON{
		RouteLookupConfig: rlcJSON, // "JSON form of RouteLookupClusterSpecifier.config" - RLS in xDS Design Doc
		ChildPolicy: []map[string]json.RawMessage{
			{
				"cds_experimental": json.RawMessage(`{"isDynamic":true}`),
			},
		},
		ChildPolicyConfigTargetFieldName: "cluster",
	}

	rawJSON, err := json.Marshal(lbCfgJSON)
	if err != nil {
		return nil, fmt.Errorf("rls_csp: error marshaling load balancing config %v: %v", lbCfgJSON, err)

View on GitHub (pinned to 0c51461d27)