dgraph-io/dgraph · error
unable to unmarshal ACL: %v :: %w
Error message
unable to unmarshal ACL: %v :: %w
What it means
Each group's ACL field is a JSON document of old-style rules. upgradeACLRules unmarshals it into a rules struct; if the stored JSON is malformed or its shape changed (e.g. fields renamed between versions), json.Unmarshal fails and the error is wrapped with the offending ACL text and the underlying parse error.
Source
Thrown at upgrade/change_v20.03.0.go:62
if err := getQueryResult(dg, queryACLGroupsBefore_v20_03_0, &data); err != nil {
return fmt.Errorf("error querying old ACL rules: %w", err)
}
groups, ok := data["rules"]
if !ok {
return fmt.Errorf("unable to parse ACLs: %v", data)
}
counter := 1
var nquads []*api.NQuad
for _, group := range groups {
if group.ACL == "" {
continue
}
var rs rules
if err := json.Unmarshal([]byte(group.ACL), &rs); err != nil {
return fmt.Errorf("unable to unmarshal ACL: %v :: %w", group.ACL, err)
}
for _, r := range rs {
newRuleStr := fmt.Sprintf("_:newrule%d", counter)
nquads = append(nquads, []*api.NQuad{
// the name of the type was Rule in v20.03.0
getTypeNquad(newRuleStr, "Rule"),
{
Subject: newRuleStr,
Predicate: "dgraph.rule.predicate",
ObjectValue: &api.Value{
Val: &api.Value_StrVal{StrVal: r.Predicate},
},
},
{
Subject: newRuleStr,
Predicate: "dgraph.rule.permission",
ObjectValue: &api.Value{View on GitHub (pinned to 759e242be6)
Solutions
- Inspect the ACL string printed in the error and fix invalid JSON directly in the graph before re-running the upgrade
- Restore the affected dgraph.group.acl node from a backup taken before the corruption
- Delete the malformed group ACL node if the group is no longer needed, then re-run the upgrade
- Verify the JSON matches the old v20.03 Rule schema (permission as map of predicate->int32, etc.)
Example fix
// corrupt node in graph
{"rules":[{"permission":{"chat":1},"predicate":"chat"} // truncated
// after (fixed dgraph.group.acl JSON)
{"rules":[{"permission":{"chat":1},"predicate":"chat"}]} Defensive patterns
Strategy: validation
Validate before calling
var probe map[string]json.RawMessage
if err := json.Unmarshal([]byte(group.ACL), &probe); err != nil {
return fmt.Errorf("skip corrupt ACL JSON for group %s: %w", group.Name, err)
} Type guard
func validACLJSON(s string) bool {
var rs rules
return s != "" && json.Unmarshal([]byte(s), &rs) == nil
} Try / catch
if err := upgradeACLRules(); err != nil {
if strings.Contains(err.Error(), "unable to unmarshal ACL") {
// extract the corrupt ACL from the message, fix/restore the node, rerun
}
return err
} Prevention
- Never hand-edit dgraph.group.acl JSON via raw mutations; use the ACL API
- Take a backup before upgrading so corrupt nodes can be restored
- Validate stored ACL JSON (jq or json.Unmarshal probe) before running the migration
When it happens
Trigger: A dgraph.group.acl node whose ACL JSON was hand-edited, truncated, or written by an incompatible Dgraph version, so json.Unmarshal([]byte(group.ACL), &rs) fails during the 20.03 upgrade.
Common situations: Clusters where ACL rules were modified directly via mutations bypassing the ACL API; partial writes from a crashed earlier upgrade; custom rule objects that don't match the expected old Rule schema (permission maps, etc.).
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- unable to parse ACLs: %v
- error querying old ACL rules: %w
- error upgrading ACL rules: %w
- error deleting old acl predicates: %w
- error deleting old predicate %s
AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01).
Data as JSON: /api/errors/e23819fb341ca263.
Report an issue: GitHub.