dgraph-io/dgraph · error
ACL predicates can't be deleted
Error message
ACL predicates can't be deleted
What it means
Error returned by the ACL layer in edgraph/access.go when a mutation attempts to delete predicates that are reserved for access control (e.g. dgraph.xid, dgraph.password, dgraph.user.group or other ACL-internal predicates). Fix by excluding ACL predicates from the deletion.
Source
Thrown at edgraph/access.go:819
// as a byproduct, it also sets the userId and groups
doAuthorizeMutation := func() error {
userData, err := extractUserAndGroups(ctx)
if err != nil {
// We don't follow fail open approach anymore.
return status.Error(codes.Unauthenticated, err.Error())
}
userId = userData.userId
groupIds = userData.groupIds
if x.IsSuperAdmin(groupIds) {
// Members of guardians group are allowed to mutate anything
// (including delete) except the permission of the acl predicates.
switch {
case isAclPredMutation(gmu.Set):
return errors.Errorf("the permission of ACL predicates can not be changed")
case isAclPredMutation(gmu.Del):
return errors.Errorf("ACL predicates can't be deleted")
}
if !shouldAllowAcls(userData.namespace) {
for _, pred := range preds {
if x.IsAclPredicate(pred) {
return status.Errorf(codes.PermissionDenied,
"unauthorized to mutate acl predicates: %s\n", pred)
}
}
}
return nil
}
result := authorizePreds(ctx, userData, preds, acl.Write)
if len(result.blocked) > 0 {
var msg strings.Builder
for key := range result.blocked {
x.Check2(msg.WriteString(key))
x.Check2(msg.WriteString(" "))
}View on GitHub (pinned to 759e242be6)
Solutions
- Narrow delete patterns to exclude ACL predicates (avoid `* * .` wildcards on ACL-owned nodes)
- Use `dgraph acl` CLI to manage/remove ACL rules instead of raw delete mutations
- List the exact predicates you intend to delete and verify none match x.IsAclPredicate
- For full resets, use DropAll as a guardian rather than targeted deletes
Example fix
// before
del.Nquads = []string{fmt.Sprintf("<%s> * * .", uid)} // can hit ACL preds
// after
del.Nquads = []string{fmt.Sprintf("<%s> <app.pred1> * .", uid), fmt.Sprintf("<%s> <app.pred2> * .", uid)} Defensive patterns
Strategy: validation
Validate before calling
// Expand wildcard deletes explicitly and filter ACL predicates
const targets = ['app.pred1', 'app.pred2']
if (targets.some(p => p.startsWith('dgraph.'))) {
throw new Error('refusing to delete ACL predicates')
} Type guard
function isSafeDelete(preds) {
return preds.every(p => !String(p).startsWith('dgraph.'))
} Try / catch
try {
await dg.mutate(delMutation)
} catch (e) {
if (/ACL predicates can't be deleted/.test(e.message)) {
// rewrite mutation without dgraph.* predicates and retry once
}
throw e
} Prevention
- Avoid `S * * .` wildcard deletes on nodes that may own ACL predicates
- Keep ACL rule management exclusively in `dgraph acl` workflows
- Review generated N-Quads in tests for any dgraph.* predicate writes
When it happens
Trigger: A guardian sends a Del mutation whose predicates include ACL permission predicates (matched by isAclPredMutation(gmu.Del)), e.g. dropping nodes with wildcard predicate deletion that sweeps in dgraph.group.acl.
Common situations: Drop-by-uid wildcard deletes (`S * * .`) that unintentionally include ACL predicates; cleanup scripts purging all data for a namespace; copying delete logic from non-ACL clusters.
Related errors
- the permission of ACL predicates can not be changed
- only guardians are allowed to drop all data, but the current
- cannot force namespace %#x when provided creds are not of su
- Multiple groot users found
- Error while parsing Uid: %s of groot user
AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01).
Data as JSON: /api/errors/0f200bea74ee467a.
Report an issue: GitHub.