grpc/grpc-go · error

rbac: error constructing matching engine: %v

Error message

rbac: error constructing matching engine: %v

What it means

The RBAC filter builds a matching chain engine from the rules via rbac.NewChainEngine. If construction fails (e.g. an unsupported matcher variant, malformed regex, malformed CIDR), the underlying error is wrapped and returned, but only when the action is not LOG (LOG-action policies are silently treated as no-op).

Source

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

	// Two cases where this HTTP Filter is a no op:
	// "If absent, no enforcing RBAC policy will be applied" - RBAC
	// Documentation for Rules field.
	// "At this time, if the RBAC.action is Action.LOG then the policy will be
	// completely ignored, as if RBAC was not configured." - A41
	if rbacCfg.Rules == nil || rbacCfg.GetRules().GetAction() == v3rbacpb.RBAC_LOG {
		return config{}, nil
	}

	// TODO(gregorycooke) - change the call chain to here so we have the filter
	// name to input here instead of an empty string. It will come from here:
	// https://github.com/grpc/grpc-go/blob/eff0942e95d93112921414aee758e619ec86f26f/xds/internal/xdsclient/xdsresource/unmarshal_lds.go#L199
	ce, err := rbac.NewChainEngine([]*v3rbacpb.RBAC{rbacCfg.GetRules()}, "")
	if err != nil {
		// "At this time, if the RBAC.action is Action.LOG then the policy will be
		// completely ignored, as if RBAC was not configured." - A41
		if rbacCfg.GetRules().GetAction() != v3rbacpb.RBAC_LOG {
			return nil, fmt.Errorf("rbac: error constructing matching engine: %v", err)
		}
	}

	return config{chainEngine: ce}, nil
}

func (builder) ParseFilterConfig(cfg proto.Message) (httpfilter.FilterConfig, error) {
	if cfg == nil {
		return nil, fmt.Errorf("rbac: nil configuration message provided")
	}
	m, ok := cfg.(*anypb.Any)
	if !ok {
		return nil, fmt.Errorf("rbac: error parsing config %v: unknown type %T", cfg, cfg)
	}
	msg := new(rpb.RBAC)
	if err := m.UnmarshalTo(msg); err != nil {
		return nil, fmt.Errorf("rbac: error parsing config %v: %v", cfg, err)
	}

View on GitHub (pinned to 03255a9237)

Solutions

  1. Read the wrapped error (the %v) to find the specific matcher the ChainEngine rejected.
  2. Fix the offending matcher (regex escaping, CIDR notation, supported matcher kind) in the control-plane policy.
  3. If the matcher requires a newer Envoy feature, either downgrade the policy or upgrade grpc-go to a version that supports it.

Example fix

// before: permission with a malformed regex
//   - header:
//       name: x-trace-id
//       safe_regex_match: { regex: "[a-z" }   // unterminated
//
// after
//   - header:
//       name: x-trace-id
//       safe_regex_match: { regex: "[a-z]+" }
Defensive patterns

Strategy: validation

Validate before calling

// Pre-build the chain engine on the control plane (or in a test) to catch
// matcher errors before serving the resource.
func preflightChainEngine(rules *rbacpb.RBAC) error {
	_, err := rbacfilter.NewChainEngine([]*rbacpb.RBAC{rules}, "")
	return err
}

Try / catch

// When consuming xDS updates, isolate RBAC parse failures so one bad
// resource does not tear down the whole listener.
//   fc, err := builder.ParseFilterConfig(anyCfg)
//   if err != nil {
//       log rbac failure, nack the resource, keep previous config
//   }

Prevention

When it happens

Trigger: A structurally-valid RBAC protobuf whose matchers are semantically invalid is delivered by the control plane: bad regex in a string matcher, malformed IP/CIDR range, or a matcher variant that grpc-go's ChainEngine does not implement.

Common situations: Control-plane/Envoy version newer than the grpc-go RBAC implementation emitting a matcher type grpc-go cannot compile; hand-authored policy with an invalid regex; partial proto from a buggy xDS server.

Related errors


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