grpc/grpc-go · error

rbac: policy.CheckedCondition is present

Error message

rbac: policy.CheckedCondition is present

What it means

Returned by the RBAC HTTP filter's parseConfig (rbac.go:66-67) when any policy has its checked_condition field set. checked_condition is the 'safe-to-log' CEL variant, but gRPC RBAC (per gRFC A41) implements neither condition nor checked_condition, so its presence is a validation failure. The check runs right after the condition check in the same policy loop.

Source

Thrown at internal/xds/httpfilter/rbac/rbac.go:67

func (builder) TypeURLs() []string {
	return []string{
		"type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC",
		"type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBACPerRoute",
	}
}

// Parsing is the same for the base config and the override config.
func parseConfig(rbacCfg *rpb.RBAC) (httpfilter.FilterConfig, error) {
	// All the validation logic described in A41.
	for _, policy := range rbacCfg.GetRules().GetPolicies() {
		// "Policy.condition and Policy.checked_condition must cause a
		// validation failure if present." - A41
		if policy.Condition != nil {
			return nil, errors.New("rbac: Policy.condition is present")
		}
		if policy.CheckedCondition != nil {
			return nil, errors.New("rbac: policy.CheckedCondition is present")
		}

		// "It is also a validation failure if Permission or Principal has a
		// header matcher for a grpc- prefixed header name or :scheme." - A41
		for _, principal := range policy.Principals {
			name := principal.GetHeader().GetName()
			if name == ":scheme" || strings.HasPrefix(name, "grpc-") {
				return nil, fmt.Errorf("rbac: principal header matcher for %v is :scheme or starts with grpc", name)
			}
		}
		for _, permission := range policy.Permissions {
			name := permission.GetHeader().GetName()
			if name == ":scheme" || strings.HasPrefix(name, "grpc-") {
				return nil, fmt.Errorf("rbac: permission header matcher for %v is :scheme or starts with grpc", name)
			}
		}
	}

View on GitHub (pinned to 03255a9237)

Solutions

  1. Strip the checked_condition field from every RBAC policy before serving to gRPC.
  2. Re-express the intended rule using supported permission/principal matchers.
  3. Run an xDS/RBAC pre-publish lint that rejects policies with condition or checked_condition set.

Example fix

// before
//   policies: { p1: { checked_condition: { ...CEL... }, permissions: [...] } }
// after
//   policies: { p1: { permissions: [...], principals: [...] } }  // no checked_condition
Defensive patterns

Strategy: validation

Validate before calling

func rbacPoliciesHaveNoCheckedCondition(cfg *rpb.RBAC) error {
    for _, p := range cfg.GetRules().GetPolicies() {
        if p.GetCheckedCondition() != nil {
            return fmt.Errorf("policy %q uses unsupported checked_condition", p)
        }
    }
    return nil
}

Prevention

When it happens

Trigger: An xDS RBAC HTTP filter config whose rules.policies[*].checked_condition is populated. parseConfig detects policy.CheckedCondition != nil and returns this error, NACKing the resource.

Common situations: Envoy RBAC configs that opted for checked_condition (logging-safe CEL) being served to gRPC; migrating an Envoy policy verbatim; control planes not stripping gRPC-incompatible fields.

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/d3d3682d66b1b985. Report an issue: GitHub.