argoproj/argo-workflows · error
failed to evaluate rule: %w
Error message
failed to evaluate rule: %w
What it means
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.
Source
Thrown at server/auth/gatekeeper.go:254
}
var serviceAccounts []*corev1.ServiceAccount
for _, serviceAccount := range list {
_, ok := serviceAccount.Annotations[common.AnnotationKeyRBACRule]
if !ok {
continue
}
serviceAccounts = append(serviceAccounts, serviceAccount)
}
sort.Slice(serviceAccounts, func(i, j int) bool { return precedence(serviceAccounts[i]) > precedence(serviceAccounts[j]) })
for _, serviceAccount := range serviceAccounts {
rule := serviceAccount.Annotations[common.AnnotationKeyRBACRule]
v, err := jsonutil.Jsonify(claims)
if err != nil {
return nil, fmt.Errorf("failed to marshall claims: %w", err)
}
allow, err := argoexpr.EvalBool(rule, v)
if err != nil {
return nil, fmt.Errorf("failed to evaluate rule: %w", err)
}
if !allow {
continue
}
return serviceAccount, nil
}
return nil, fmt.Errorf("no service account rule matches")
}
func (s *gatekeeper) canDelegateRBACToRequestNamespace(req any) bool {
if s.namespaced || os.Getenv("SSO_DELEGATE_RBAC_TO_NAMESPACE") != "true" {
return false
}
namespace := getNamespace(req)
return len(namespace) != 0 && s.ssoNamespace != namespace
}
func (s *gatekeeper) getClientsForServiceAccount(ctx context.Context, claims *authTypes.Claims, serviceAccount *corev1.ServiceAccount) (*servertypes.Clients, error) {View on GitHub (pinned to 35bff19146)
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.
Example fix
// before: broken annotation (unquoted, missing dot-escape, type mismatch)
metadata:
annotations:
workflows.argoproj.io/rbac-rule: email.endsWith(@example.com) && sub == 123
// after
metadata:
annotations:
workflows.argoproj.io/rbac-rule: 'email.endsWith("@example.com") && sub == "123"' Defensive patterns
Strategy: validation
Validate before calling
// validate rbac-rule annotations before applying
for sa in $(kubectl -n argo get sa -o name); do
rule=$(kubectl -n argo get $sa -o jsonpath='{.metadata.annotations.workflows\.argoproj\.io/rbac-rule}')
[ -n "$rule" ] && echo "$sa: $rule" # review quoting/claim names
done Try / catch
// operator-side: the server converts this to PermissionDenied
if st, ok := status.FromError(err); ok && st.Code() == codes.PermissionDenied {
log.Printf("SSO RBAC denied; check rbac-rule annotations: %v", st.Message())
} Prevention
- 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')
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- no service account rule matches
- failed to list SSO RBAC service accounts: %w
- failed to marshall claims: %w
- failed to get service account secret: %w
- failed to create secret: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/630b4a98abf204e2.
Report an issue: GitHub.