grpc/grpc-go · error
failed to unmarshal policy
Error message
failed to unmarshal policy: %v
What it means
Returned by translatePolicy (rbac_translator.go:367) when the authorization policy JSON cannot be decoded into authorizationPolicy. The decoder uses DisallowUnknownFields (line 365), so the error fires on malformed JSON, wrong types, or any unrecognized field name. The wrapped %v is the encoding/json error.
Solutions
- Validate the JSON with a JSON parser and check the wrapped error for line/field detail; remove or rename unknown fields.
- Match the field names exactly: name, deny_rules, allow_rules, audit_logging_options (and within rules: name, source, request, paths, headers).
- Strip comments/trailing commas; the policy is strict JSON.
- Reload via the file watcher to keep the last good policy while you fix the file.
Example fix
// before
{ "name": "p", "allow_rule": [ {"name":"r"} ] } // typo + unknown field
// after
{ "name": "p", "allow_rules": [ {"name":"r","request":{"paths":["/"]}} ] } Defensive patterns
Strategy: validation
Validate before calling
// Validate JSON shape and unknown fields before loading.
func validatePolicyJSON(s string) error {
p := &authorizationPolicy{}
d := json.NewDecoder(strings.NewReader(s))
d.DisallowUnknownFields()
return d.Decode(p)
} Try / catch
interceptor, err := authz.NewStatic(policyJSON)
if err != nil {
if strings.Contains(err.Error(), "failed to unmarshal policy") {
// json error; fix syntax/fields and reload (file watcher keeps prior policy)
}
} Prevention
- Use strict JSON (no comments/trailing commas); validate before deploy.
- Match exact field names; DisallowUnknownFields is on, so unknown keys are rejected.
- Validate with the same decoder settings the library uses.
When it happens
Trigger: Policy file/string that is not valid JSON, has a typo in a field name (e.g. "allow_rule" vs "allow_rules"), includes an unsupported field, or uses wrong value types.
Common situations: Hand-edited policy with trailing commas/comments (JSON, not JSON5); stale field names from an older policy version; extra fields that DisallowUnknownFields rejects.
Related errors
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/8aede689e0727949.
Report an issue: GitHub.
Appendix: source
Thrown at authz/rbac_translator.go:367
case v3rbacpb.RBAC_AuditLoggingOptions_ON_ALLOW:
return v3rbacpb.RBAC_AuditLoggingOptions_NONE
case v3rbacpb.RBAC_AuditLoggingOptions_ON_DENY_AND_ALLOW:
return v3rbacpb.RBAC_AuditLoggingOptions_ON_DENY
default:
return v3rbacpb.RBAC_AuditLoggingOptions_NONE
}
}
// translatePolicy translates SDK authorization policy in JSON format to two
// Envoy RBAC polices (deny followed by allow policy) or only one Envoy RBAC
// allow policy. Also returns the overall policy name. If the input policy
// cannot be parsed or is invalid, an error will be returned.
func translatePolicy(policyStr string) ([]*v3rbacpb.RBAC, string, error) {
policy := &authorizationPolicy{}
d := json.NewDecoder(bytes.NewReader([]byte(policyStr)))
d.DisallowUnknownFields()
if err := d.Decode(policy); err != nil {
return nil, "", fmt.Errorf("failed to unmarshal policy: %v", err)
}
if policy.Name == "" {
return nil, "", fmt.Errorf(`"name" is not present`)
}
if len(policy.AllowRules) == 0 {
return nil, "", fmt.Errorf(`"allow_rules" is not present`)
}
allowLogger, denyLogger, err := policy.AuditLoggingOptions.toProtos()
if err != nil {
return nil, "", err
}
rbacs := make([]*v3rbacpb.RBAC, 0, 2)
if len(policy.DenyRules) > 0 {
denyPolicies, err := parseRules(policy.DenyRules, policy.Name)
if err != nil {
return nil, "", fmt.Errorf(`"deny_rules" %v`, err)
}
denyRBAC := &v3rbacpb.RBAC{View on GitHub (pinned to 0c51461d27)