{"record":{"id":"2629d040aadf4688","repo":"grpc/grpc-go","slug":"deny-rules-v","errorCode":null,"errorMessage":"\"deny_rules\" %v","messagePattern":"\"deny_rules\" (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"authz/rbac_translator.go","lineNumber":383,"sourceCode":"\td.DisallowUnknownFields()\n\tif err := d.Decode(policy); err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"failed to unmarshal policy: %v\", err)\n\t}\n\tif policy.Name == \"\" {\n\t\treturn nil, \"\", fmt.Errorf(`\"name\" is not present`)\n\t}\n\tif len(policy.AllowRules) == 0 {\n\t\treturn nil, \"\", fmt.Errorf(`\"allow_rules\" is not present`)\n\t}\n\tallowLogger, denyLogger, err := policy.AuditLoggingOptions.toProtos()\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\trbacs := make([]*v3rbacpb.RBAC, 0, 2)\n\tif len(policy.DenyRules) > 0 {\n\t\tdenyPolicies, err := parseRules(policy.DenyRules, policy.Name)\n\t\tif err != nil {\n\t\t\treturn nil, \"\", fmt.Errorf(`\"deny_rules\" %v`, err)\n\t\t}\n\t\tdenyRBAC := &v3rbacpb.RBAC{\n\t\t\tAction:              v3rbacpb.RBAC_DENY,\n\t\t\tPolicies:            denyPolicies,\n\t\t\tAuditLoggingOptions: denyLogger,\n\t\t}\n\t\trbacs = append(rbacs, denyRBAC)\n\t}\n\tallowPolicies, err := parseRules(policy.AllowRules, policy.Name)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(`\"allow_rules\" %v`, err)\n\t}\n\tallowRBAC := &v3rbacpb.RBAC{Action: v3rbacpb.RBAC_ALLOW, Policies: allowPolicies, AuditLoggingOptions: allowLogger}\n\treturn append(rbacs, allowRBAC), policy.Name, nil\n}\n","sourceCodeStart":365,"sourceCodeEnd":399,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/authz/rbac_translator.go#L365-L399","documentation":"Returned by translatePolicy (rbac_translator.go:383) wrapping a failure from parseRules(policy.DenyRules, policy.Name). It carries the index and sub-error of the first invalid deny rule (same rule format as allow_rules: each needs a name and a valid request block). The %v is the underlying parseRules error such as a missing rule name or bad header matcher.","triggerScenarios":"A deny_rules[] entry missing \"name\", or whose request.headers/paths are malformed; deny_rules is optional but if present each entry is fully validated.","commonSituations":"Adding deny rules modeled after allow rules but omitting required sub-fields; copy-paste errors.","solutions":["Read the wrapped %v to find the offending deny rule and its sub-cause (e.g. '0: \"name\" is not present'), then fix that entry.","Validate every deny_rules entry with the same checks as allow_rules (non-empty name, valid headers/paths).","Use file-watcher reload so the previous policy stays active while you correct the file."],"exampleFix":"// before\n\"deny_rules\": [ { \"request\": { \"paths\": [\"/admin\"] } } ]\n// error: \"deny_rules\" 0: \"name\" is not present\n\n// after\n\"deny_rules\": [ { \"name\": \"block_admin\", \"request\": { \"paths\": [\"/admin\"] } } ]","handlingStrategy":"validation","validationCode":"for i, r := range denyRules {\n    if r.Name == \"\" || !validRequest(r.Request) {\n        return fmt.Errorf(\"deny_rules[%d]: invalid\", i)\n    }\n}","typeGuard":null,"tryCatchPattern":"interceptor, err := authz.NewStatic(policyJSON)\nif err != nil {\n    if strings.Contains(err.Error(), `\"deny_rules\"`) {\n        // wrapped %v names the deny-rule index + cause; fix and reload\n    }\n}","preventionTips":["Validate deny_rules with the same checks as allow_rules (name + valid request).","deny_rules is optional; if present, every entry is fully validated."],"tags":["grpc","authz","rbac","policy","config","go"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}