grpc/grpc-go · error

RLS LB policy not registered

Error message

RLS LB policy not registered

What it means

The RLS load balancer policy named 'rls_experimental' is not found in the gRPC balancer registry (rls.go:86-88). The cluster specifier plugin calls balancer.Get to locate the RLS LB policy for config validation, and a nil return means no balancer with that name has registered itself via init().

Solutions

  1. Add a blank import of the RLS balancer: import _ "google.golang.org/grpc/balancer/rls"
  2. Verify the import appears before any xDS resource processing occurs
  3. Check that build tags or build constraints are not excluding the balancer/rls package
  4. Confirm the gRPC version includes the RLS balancer (available since gRPC 1.40+)

Example fix

// before — RLS cluster specifier imported but not the RLS balancer
import (
    _ "google.golang.org/grpc/internal/xds/clusterspecifier/rls"
)

// after — also import the RLS balancer to register it
import (
    _ "google.golang.org/grpc/balancer/rls"
    _ "google.golang.org/grpc/internal/xds/clusterspecifier/rls"
)
Defensive patterns

Strategy: validation

Validate before calling

// Verify the RLS LB policy is registered at startup.
if balancer.Get(internal.RLSLoadBalancingPolicyName) == nil {
    log.Fatal("RLS LB policy not registered — add: import _ \"google.golang.org/grpc/balancer/rls\"")
}

Prevention

When it happens

Trigger: balancer.Get(internal.RLSLoadBalancingPolicyName) returns nil because the RLS balancer package (google.golang.org/grpc/balancer/rls) was never imported, so its init() function that calls balancer.Register never executed.

Common situations: Application imports the RLS cluster specifier plugin but not the RLS balancer package; using a stripped-down or custom gRPC build that excludes the RLS balancer; build tags or constraints stripping the balancer/rls package; init ordering issue.

Related errors


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

Appendix: source

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

	}
	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)
	}

	rlsBB := balancer.Get(internal.RLSLoadBalancingPolicyName)
	if rlsBB == nil {
		return nil, fmt.Errorf("RLS LB policy not registered")
	}
	if _, err = rlsBB.(balancer.ConfigParser).ParseConfig(rawJSON); err != nil {
		return nil, fmt.Errorf("rls_csp: validation error from rls lb policy parsing: %v", err)
	}

	return clusterspecifier.BalancerConfig{{internal.RLSLoadBalancingPolicyName: lbCfgJSON}}, nil
}

View on GitHub (pinned to 0c51461d27)