{"record":{"id":"630b4a98abf204e2","repo":"argoproj/argo-workflows","slug":"failed-to-evaluate-rule-w","errorCode":null,"errorMessage":"failed to evaluate rule: %w","messagePattern":"failed to evaluate rule: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/auth/gatekeeper.go","lineNumber":254,"sourceCode":"\t}\n\tvar serviceAccounts []*corev1.ServiceAccount\n\tfor _, serviceAccount := range list {\n\t\t_, ok := serviceAccount.Annotations[common.AnnotationKeyRBACRule]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tserviceAccounts = append(serviceAccounts, serviceAccount)\n\t}\n\tsort.Slice(serviceAccounts, func(i, j int) bool { return precedence(serviceAccounts[i]) > precedence(serviceAccounts[j]) })\n\tfor _, serviceAccount := range serviceAccounts {\n\t\trule := serviceAccount.Annotations[common.AnnotationKeyRBACRule]\n\t\tv, err := jsonutil.Jsonify(claims)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to marshall claims: %w\", err)\n\t\t}\n\t\tallow, err := argoexpr.EvalBool(rule, v)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to evaluate rule: %w\", err)\n\t\t}\n\t\tif !allow {\n\t\t\tcontinue\n\t\t}\n\t\treturn serviceAccount, nil\n\t}\n\treturn nil, fmt.Errorf(\"no service account rule matches\")\n}\n\nfunc (s *gatekeeper) canDelegateRBACToRequestNamespace(req any) bool {\n\tif s.namespaced || os.Getenv(\"SSO_DELEGATE_RBAC_TO_NAMESPACE\") != \"true\" {\n\t\treturn false\n\t}\n\tnamespace := getNamespace(req)\n\treturn len(namespace) != 0 && s.ssoNamespace != namespace\n}\n\nfunc (s *gatekeeper) getClientsForServiceAccount(ctx context.Context, claims *authTypes.Claims, serviceAccount *corev1.ServiceAccount) (*servertypes.Clients, error) {","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/server/auth/gatekeeper.go#L236-L272","documentation":"getServiceAccount evaluates each ServiceAccount's workflows.argoproj.io/rbac-rule annotation as a bool expression (argoexpr.EvalBool) against the OIDC claims. This error is returned when the rule expression is invalid: bad syntax, references to fields not present in the claims JSON, or wrong types (e.g. comparing a string to a number). Because the code returns on the first failing rule rather than skipping it, one broken rule annotation can break SSO login for every user, even those who would match a later, valid rule.","triggerScenarios":"An SSO request with RBAC enabled hits a ServiceAccount whose rbac-rule annotation is not a syntactically valid expr-lang expression, or references claim keys/values that don't exist or have mismatched types (e.g. `sub == 123` when sub is a string, unknown identifiers like `groups` when the IDP doesn't emit them).","commonSituations":"Typos in the rbac-rule annotation (yaml quoting stripped operators), rules copied from docs that use claims your OIDC provider doesn't provide (e.g. email for IDPs that hide emails), numeric-vs-string comparisons, and unquoted special characters in YAML.","solutions":["Fix the rbac-rule annotation on the offending ServiceAccount so it is a valid expr expression, e.g. `\"workflows.argoproj.io/rbac-rule\": \"email.endsWith('@example.com')\"` with proper YAML quoting.","Verify claim field names/types by logging the claims or testing a rule like `true`; replace direct string/number comparisons with matching types (e.g. `sub == \"user@x\"` not `sub == 123`).","Quote the whole rule in YAML (single quotes) so special chars aren't parsed by YAML; then re-check with `kubectl get sa -o yaml`.","Test locally: `argo server --auth-mode sso` with RBAC enabled and inspect the 'failed to perform RBAC authorization' log line for the wrapped cause."],"exampleFix":"// before: broken annotation (unquoted, missing dot-escape, type mismatch)\nmetadata:\n  annotations:\n    workflows.argoproj.io/rbac-rule: email.endsWith(@example.com) && sub == 123\n// after\nmetadata:\n  annotations:\n    workflows.argoproj.io/rbac-rule: 'email.endsWith(\"@example.com\") && sub == \"123\"'","handlingStrategy":"validation","validationCode":"// validate rbac-rule annotations before applying\nfor sa in $(kubectl -n argo get sa -o name); do\n  rule=$(kubectl -n argo get $sa -o jsonpath='{.metadata.annotations.workflows\\.argoproj\\.io/rbac-rule}')\n  [ -n \"$rule\" ] && echo \"$sa: $rule\"   # review quoting/claim names\ndone","typeGuard":null,"tryCatchPattern":"// operator-side: the server converts this to PermissionDenied\nif st, ok := status.FromError(err); ok && st.Code() == codes.PermissionDenied {\n    log.Printf(\"SSO RBAC denied; check rbac-rule annotations: %v\", st.Message())\n}","preventionTips":["Single-quote rules in YAML so expr syntax survives","Test each rule against real IDP claims (decode the ID token) before rollout","Avoid strict type comparisons on claim values (sub, iat are strings)","Keep one known-good catch-all rule with low precedence (rule: 'true')"],"tags":["sso","rbac","expression-evaluation","misconfiguration"],"backgroundTag":"rbac-rule-expression-invalid","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}