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
- 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.
- 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.
- 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
- Validate each rule's request.headers and request.paths before deploying.
- Parse the composite error: leading index is the rule, remainder is the field cause.
- Use file-watcher reload to keep serving the previous good policy.
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
- "allow_rules" is not present
- "allow_rules
- : "name" is not present
- "deny_rules
- failed to parse AuditCondition
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)