grpc/grpc-go · error
rls_csp: error parsing config %v: unknown type %T
Error message
rls_csp: error parsing config %v: unknown type %T
What it means
Returned by ParseClusterSpecifierConfig when cfg is non-nil but not a *anypb.Any. The clusterspecifier framework always wraps configs as *anypb.Any, so reaching this branch means the framework or a custom caller bypassed that contract.
Source
Thrown at internal/xds/clusterspecifier/rls/rls.go:60
return []string{"type.googleapis.com/grpc.lookup.v1.RouteLookupClusterSpecifier"}
}
// lbConfigJSON is the RLS LB Policies configuration in JSON format.
// RouteLookupConfig will be a raw JSON string from the passed in proto
// 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",View on GitHub (pinned to 03255a9237)
Solutions
- When calling ParseClusterSpecifierConfig directly, wrap the proto with anypb.New first.
- If this surfaces through the normal xDS path, it is a framework bug — report it with the resource that triggered it.
Example fix
// before
b, err := rls{}.ParseClusterSpecifierConfig(rlcs) // *RouteLookupClusterSpecifier
// after
any, _ := anypb.New(rlcs)
b, err := rls{}.ParseClusterSpecifierConfig(any) Defensive patterns
Strategy: type-guard
Type guard
func isAnyProto(m proto.Message) (*anypb.Any, bool) {
a, ok := m.(*anypb.Any)
return a, ok
} Prevention
- Always wrap configs in *anypb.Any before passing to clusterspecifier parsers.
- Let the framework Any-wrap; avoid calling ParseClusterSpecifierConfig with raw protos.
- Add a type assertion in test helpers to fail fast on misuse.
When it happens
Trigger: A direct call to ParseClusterSpecifierConfig with a concrete proto type (e.g. *rlspb.RouteLookupClusterSpecifier) instead of *anypb.Any, or a framework integration bug that does not Any-wrap.
Common situations: Unit tests or custom clusterspecifier plumbing that invoke the parser directly with a raw proto; normal xDS-driven parsing always supplies *anypb.Any.
Related errors
- rls_csp: nil configuration message provided
- rls_csp: error parsing config %v: %v
- rls_csp: error marshaling route lookup config: %v: %v
- rls_csp: error marshaling load balancing config %v: %v
- RLS LB policy not registered
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/df2b7e46195eb861.
Report an issue: GitHub.