grpc/grpc-go · error
rbac: Policy.condition is present
Error message
rbac: Policy.condition is present
What it means
When the RBAC HTTP filter parses its config (internal/xds/httpfilter/rbac/rbac.go:59, parseConfig), it enforces gRFC A41: the `condition` field of an RBAC Policy is not supported by gRPC and must cause a validation failure if present. The check at line 64-66 returns this error for any policy whose `Condition` is non-nil. gRPC deliberately rejects CEL-based conditions because the gRPC RBAC engine does not evaluate CEL expressions.
Solutions
- Remove the `condition` field from any RBAC policy that will be consumed by gRPC clients — express the same logic via permissions/principals matchers instead.
- If the policy must keep the condition for Envoy, scope it (e.g. via RBACPerRoute or a separate filter chain) so it does not reach gRPC.
- Upgrade the control plane to a version that omits `condition` for gRPC-targeted policies, or filter it at the xDS server.
Example fix
// before (Envoy/Istio RBAC policy)
policies:
p1:
condition: "request.host == 'x'"
permissions: [...]
// after: express via principal/permission matchers only
policies:
p1:
permissions:
- any: true
principals:
- header: { name: "host", exactMatch: "x" } Defensive patterns
Strategy: validation
Validate before calling
// Validate an RBAC policy proto before it is sent on to gRPC clients.
func validateRBACPolicyForGRPC(rbac *rpb.RBAC) error {
for name, p := range rbac.GetRules().GetPolicies() {
if p.GetCondition() != nil {
return fmt.Errorf("policy %q: gRPC does not support Policy.condition", name)
}
// also see error 73 for CheckedCondition
}
return nil
} Prevention
- Author RBAC policies for gRPC using only permission/principal matchers — never CEL conditions.
- Add a CI check that rejects any RBAC config containing `condition` before it reaches gRPC clients.
- Document which Envoy RBAC features gRPC supports (per gRFC A41) for policy authors.
When it happens
Trigger: Triggered when an xDS server delivers an RBAC HTTP filter config (envoy.extensions.filters.http.rbac.v3.RBAC) whose Rules.Policies entry has a non-nil `condition` field. The error surfaces during xDS resource processing, NACKing the response.
Common situations: An Envoy/Istio configuration authored for Envoy that uses CEL `condition` blocks is applied to a gRPC client; a control-plane policy written without awareness of gRPC's A41 restrictions; sharing an RBAC policy between Envoy sidecars and gRPC xDS clients.
Related errors
- rbac: policy.CheckedCondition is present
- message authentication failed
- server-side auth info is not of type alts.AuthInfo
- unknown header matcher type
- all SubConns are in TransientFailure
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/51eb67bae2ad6a48.
Report an issue: GitHub.
Appendix: source
Thrown at internal/xds/httpfilter/rbac/rbac.go:65
httpfilter.FilterConfig
chainEngine *rbac.ChainEngine
}
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.
//
// "Envoy aliases :authority and Host in its header map implementation,
// so they should be treated equivalent for the RBAC matchers; there must
// be no behavior change depending on which of the two header names is
// used in the RBAC policy." - A41. Any header matcher with value "host"
// is rewritten to ":authority", as that is what grpc-go shifts both
// headers to in the transport layer.
//
// Both rules apply to header matchers nested inside and/or/not rules, so
// the whole permission and principal trees are walked.
for _, principal := range policy.GetPrincipals() {View on GitHub (pinned to 0c51461d27)