{"record":{"id":"639d77e09985bc04","repo":"grpc/grpc-go","slug":"rls-call-throttled-at-client-side","errorCode":null,"errorMessage":"RLS call throttled at client side","messagePattern":"RLS call throttled at client side","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"balancer/rls/picker.go","lineNumber":40,"sourceCode":"\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"google.golang.org/grpc/balancer\"\n\t\"google.golang.org/grpc/balancer/rls/internal/keys\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/connectivity\"\n\testats \"google.golang.org/grpc/experimental/stats\"\n\tinternalgrpclog \"google.golang.org/grpc/internal/grpclog\"\n\trlspb \"google.golang.org/grpc/internal/proto/grpc_lookup_v1\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"google.golang.org/grpc/status\"\n)\n\nvar (\n\terrRLSThrottled = errors.New(\"RLS call throttled at client side\")\n\n\t// Function to compute data cache entry size.\n\tcomputeDataCacheEntrySize = dcEntrySize\n)\n\n// exitIdler wraps the only method on the BalancerGroup that the picker calls.\ntype exitIdler interface {\n\tExitIdleOne(id string)\n}\n\n// rlsPicker selects the subConn to be used for a particular RPC. It does not\n// manage subConns directly and delegates to pickers provided by child policies.\ntype rlsPicker struct {\n\t// The keyBuilder map used to generate RLS keys for the RPC. This is built\n\t// by the LB policy based on the received ServiceConfig.\n\tkbm keys.BuilderMap\n\t// Endpoint from the user's original dial target. Used to set the `host_key`\n\t// field in `extra_keys`.","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/balancer/rls/picker.go#L22-L58","documentation":"Thrown by StringMatcherFromProto when a StringMatcher's SafeRegex match pattern fails to compile as a Go RE2 regular expression via regexp.Compile. The xDS StringMatcher SafeRegex variant expects an RE2-compatible pattern; if the pattern contains unsupported syntax (e.g., backreferences, lookahead) or is malformed, compilation fails. The error wraps the offending pattern for diagnosis.","triggerScenarios":"An xDS resource (route match, RBAC header matcher, path matcher, authenticated principal matcher) specifies a string matcher with safe_regex whose regex field is syntactically invalid or uses PCRE-only features not supported by Go's RE2 engine. For example, a pattern like '(?P<name>...)\\k<name>' (named backreference) will fail because RE2 does not support backreferences.","commonSituations":"Patterns ported from Envoy's default regex engine that have wider syntax support. A control plane that passes user-supplied regex strings without validation. Patterns with unescaped special characters or mismatched parentheses. An RE2-incompatible construct like \\1 backreferences or lookbehind (?<=...).","solutions":["Test the regex against Go's regexp package: if regexp.MustCompile(pattern) fails locally, the pattern is incompatible — rewrite it to RE2 syntax.","Remove backreferences, lookahead, and lookbehind constructs; RE2 only supports leftmost-longest matching without them.","If the pattern is used for simple matching, consider switching the StringMatcher to exact, prefix, suffix, or contains variants which do not require regex compilation."],"exampleFix":"// before (control plane config with RE2-incompatible regex):\nstring_matcher:\n  safe_regex:\n    regex: \"^(foo)\\1$\"  // backreference - unsupported by RE2\n\n// after:\nstring_matcher:\n  safe_regex:\n    regex: \"^foofoo$\"  // equivalent, RE2-compatible","handlingStrategy":"validation","validationCode":"// Pre-compile regex patterns to verify RE2 compatibility before sending them in xDS:\nfunc validateSafeRegex(pattern string) error {\n    if _, err := regexp.Compile(pattern); err != nil {\n        return fmt.Errorf(\"regex %q is not RE2-compatible: %w\", pattern, err)\n    }\n    return nil\n}\n\n// Usage before building the StringMatcher proto:\nfor _, p := range policies {\n    for _, perm := range p.GetPermissions() {\n        if h := perm.GetHeader(); h != nil {\n            if sm := h.GetStringMatch(); sm != nil {\n                if sr := sm.GetSafeRegex(); sr != nil {\n                    if err := validateSafeRegex(sr.GetRegex()); err != nil {\n                        return err\n                    }\n                }\n            }\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Test all regex patterns with Go's regexp package before embedding them in xDS configs.","Avoid backreferences ((.*)\\1), lookahead (?=), and lookbehind (?<=) — use explicit alternation or anchoring instead.","Prefer exact/prefix/suffix/contains matchers over regex when possible; they are faster and cannot fail at compile time."],"tags":["xds","matcher","grpc","regex","re2"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}