argoproj/argo-workflows · error

failed to marshall claims: %w

Error message

failed to marshall claims: %w

What it means

During SSO RBAC authorization, argo-server's getServiceAccount iterates ServiceAccounts annotated with workflows.argoproj.io/rbac-rule and evaluates each rule against the JSON-serialized OIDC claims. This error is returned when jsonutil.Jsonify(claims) fails to serialize the claims struct to the value map fed into the expr evaluator. In practice the claims struct is always plain JSON-marshalable data, so this almost always indicates an internal/unexpected failure rather than a user config problem; note the serialization is needlessly repeated inside the loop, so a marshal failure blocks matching any rule.

Source

Thrown at server/auth/gatekeeper.go:250

func (s *gatekeeper) getServiceAccount(claims *authTypes.Claims, namespace string) (*corev1.ServiceAccount, error) {
	list, err := s.cache.ServiceAccountLister.ServiceAccounts(namespace).List(labels.Everything())
	if err != nil {
		return nil, fmt.Errorf("failed to list SSO RBAC service accounts: %w", err)
	}
	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)

View on GitHub (pinned to 35bff19146)

Solutions

  1. Restart argo-server and retry the request; if persistent, capture the full error (wrapped %w cause) and file an issue with server logs.
  2. Check that your argo-server image is an unmodified official release; custom patches to server/auth or serviceaccount claims types are the most likely culprit.
  3. Upgrade to a recent argo-workflows release, since the claims-to-JSON path has been refactored over versions.
Defensive patterns

Strategy: try-catch

Try / catch

// client side: gRPC unauthenticated error
_, err := client.WorkflowService.ListWorkflows(ctx, req)
if err != nil {
    if st, ok := status.FromError(err); ok && st.Code() == codes.Unauthenticated && strings.Contains(st.Message(), "not allowed") {
        // surface server logs; report bug if 'failed to marshall claims'
    }
    return err
}

Prevention

When it happens

Trigger: An SSO-authenticated gRPC/HTTP request with RBAC enabled reaches rbacAuthorization -> getServiceAccount, and jsonutil.Jsonify(*authTypes.Claims) returns an error while preparing the expression input for a ServiceAccount's rbac-rule annotation.

Common situations: Practically only seen with a corrupted/non-standard claims object, a custom or forked build that changed the Claims type, or tampered middleware state; end users rarely hit this since authTypes.Claims is a simple marshalable struct.

Related errors


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/8417174cf953c83e. Report an issue: GitHub.