grpc/grpc-go · error

%d: %v

Error message

%d: %v

What it means

Returned by parseRules (rbac_translator.go:278) wrapping a failure from parseRequest(rule.Request) for the rule at index i. parseRequest in turn calls parseHeaders/parsePaths, so this aggregates the header/path validation errors with the rule index prefix. The '%v' carries the concrete sub-error (e.g. a 'headers N: key is not present' message).

Solutions

  1. Read the wrapped error (the %v) to find the concrete cause (e.g. missing header key/values), then fix that field in the rule at the reported index.
  2. Validate each rule's request.headers and request.paths against the parser's rules (non-empty key, non-empty values, allowed header names) before deploying.
  3. Reload via the file watcher so a malformed edit keeps the prior good policy while you correct it.

Example fix

// before
"allow_rules": [
  { "name": "r1", "request": { "headers": [ {"values":["x"]} ] } }
]
// error: 0: "headers" 0: "key" is not present

// after
"allow_rules": [
  { "name": "r1", "request": { "headers": [ {"key":"authorization","values":["x"]} ] } }
]
Defensive patterns

Strategy: validation

Validate before calling

// Validate a full rule (name + request) before writing it into the policy.
func validRule(r rule) error {
    if r.Name == "" {
        return errors.New("rule name required")
    }
    for i, h := range r.Request.Headers {
        if h.Key == "" {
            return fmt.Errorf("headers %d: key required", i)
        }
        if len(h.Values) == 0 {
            return fmt.Errorf("headers %d: values required", i)
        }
    }
    return nil
}

Try / catch

interceptor, err := authz.NewStatic(policyJSON)
if err != nil {
    // err is like: 2: "headers" 0: "values" is not present
    // index 2 = the rule; inner message = the field to fix
}

Prevention

When it happens

Trigger: A rule in allow_rules/deny_rules whose request block contains an invalid path/header definition; the wrapped error pinpoints the field.

Common situations: Composite policy errors where the rule name is fine but its request matchers are malformed.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/421b952590e49e7e. Report an issue: GitHub.

Appendix: source

Thrown at authz/rbac_translator.go:278

	if len(and) > 0 {
		return permissionAnd(and), nil
	}
	return &v3rbacpb.Permission{
		Rule: &v3rbacpb.Permission_Any{
			Any: true,
		},
	}, nil
}

func parseRules(rules []rule, prefixName string) (map[string]*v3rbacpb.Policy, error) {
	policies := make(map[string]*v3rbacpb.Policy)
	for i, rule := range rules {
		if rule.Name == "" {
			return policies, fmt.Errorf(`%d: "name" is not present`, i)
		}
		permission, err := parseRequest(rule.Request)
		if err != nil {
			return nil, fmt.Errorf("%d: %v", i, err)
		}
		policyName := prefixName + "_" + rule.Name
		policies[policyName] = &v3rbacpb.Policy{
			Principals:  []*v3rbacpb.Principal{parsePeer(rule.Source)},
			Permissions: []*v3rbacpb.Permission{permission},
		}
	}
	return policies, nil
}

// Parse auditLoggingOptions to the associated RBAC protos. The single
// auditLoggingOptions results in two different parsed protos, one for the allow
// policy and one for the deny policy
func (options *auditLoggingOptions) toProtos() (allow *v3rbacpb.RBAC_AuditLoggingOptions, deny *v3rbacpb.RBAC_AuditLoggingOptions, err error) {
	allow = &v3rbacpb.RBAC_AuditLoggingOptions{}
	deny = &v3rbacpb.RBAC_AuditLoggingOptions{}

	if options.AuditCondition != "" {

View on GitHub (pinned to 0c51461d27)