{"record":{"id":"ef2286700c9cb18a","repo":"dgraph-io/dgraph","slug":"multiple-groot-users-found","errorCode":null,"errorMessage":"Multiple groot users found","messagePattern":"Multiple groot users found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"edgraph/access.go","lineNumber":590,"sourceCode":"\ttype userQryResp struct {\n\t\tGrootUser []userNode `json:\"grootUser\"`\n\t}\n\n\tvar grootUserUid string\n\tvar userResp userQryResp\n\tif err := json.Unmarshal(resp.GetJson(), &userResp); err != nil {\n\t\treturn errors.Wrap(err, \"Couldn't unmarshal response from groot user query\")\n\t}\n\tif len(userResp.GrootUser) == 0 {\n\t\t// no groot user found from query\n\t\t// Extract uid of created groot user from mutation\n\t\tnewUserUidMap := resp.GetUids()\n\t\tgrootUserUid = newUserUidMap[\"newuser\"]\n\t} else if len(userResp.GrootUser) == 1 {\n\t\t// we found a groot user\n\t\tgrootUserUid = userResp.GrootUser[0].Uid\n\t} else {\n\t\treturn errors.Wrap(err, \"Multiple groot users found\")\n\t}\n\n\tuid, err := strconv.ParseUint(grootUserUid, 0, 64)\n\tif err != nil {\n\t\treturn errors.Wrapf(err, \"Error while parsing Uid: %s of groot user\", grootUserUid)\n\t}\n\tns, err := x.ExtractNamespace(ctx)\n\tif err != nil {\n\t\treturn errors.Wrapf(err, \"While upserting user with id %s\", x.GrootId)\n\t}\n\tx.GrootUid.Store(ns, uid)\n\tglog.V(2).Infof(\"Successfully upserted groot account for namespace %d\\n\", ns)\n\treturn nil\n}\n\n// extract the userId, groupIds from the accessJwt in the context\nfunc extractUserAndGroups(ctx context.Context) (*userData, error) {\n\taccessJwt, err := x.ExtractJwt(ctx)","sourceCodeStart":572,"sourceCodeEnd":608,"githubUrl":"https://github.com/dgraph-io/dgraph/blob/759e242be62c91f8d084da06ad0c8d21256d9c07/edgraph/access.go#L572-L608","documentation":"upsertGroot looks up the 'groot' super-admin user in Dgraph. When the query returns zero or more than one groot user (the source only assigns a uid in the ==1 case), it wraps the underlying error with 'Multiple groot users found'. It indicates corrupted or duplicated ACL state in the stored data.","triggerScenarios":"Calling Reset, or any first-boot path that runs upsertGuardianAndGroot/createGuardianAndGroot, when the gql query for user 'groot' returns len(GrootUser) != 1 (0 or >1 matches) — e.g. multiple groot accounts exist in the namespace, or the groot user was never created because ACL bootstrap failed.","commonSituations":"Corrupted or manually-edited ACL data; importing data without the ACL schema/records; multi-namespace setups where groot was upserted more than once; running ACL-enabled Dgraph on a dataset bootstrapped without ACLs.","solutions":["Inspect the groot user records with a query and delete duplicates so exactly one 'groot' user exists, or recreate the ACL dataset from scratch","Re-bootstrap ACLs on a clean cluster (start with --acl and a fresh Galaxy key) so upsertGroot creates the single groot account","If groot is missing entirely, check earlier errors in upsertGuardianAndGroot (the wrapped err) — the user creation step likely failed","Disable ACL (--acl=false) only as a diagnostic, not a fix, if you don't need ACLs"],"exampleFix":"// before: multiple groot users in DB -> error\n// after: ensure exactly one groot user via query in Ratel:\n//   query { me(func: eq(dgraph.xid, \"groot\")) { uid } }\n// delete extra nodes:\n//   upsert { query {...} delete { uid <extra> * * . } }\n// then restart with ACL enabled so groot is upserted once","handlingStrategy":"validation","validationCode":"// Before relying on ACL bootstrap, verify exactly one groot user exists:\nconst q = `{ me(func: eq(dgraph.xid, \"groot\")) { uid } }`\nconst res = await dg.newTxn().query(q)\nconst users = res.data.me\nif (users.length !== 1) {\n  // clean up duplicates or re-bootstrap ACLs before proceeding\n  throw new Error(`expected 1 groot user, found ${users.length}`)\n}","typeGuard":"function hasSingleGroot(res) {\n  return Array.isArray(res?.data?.me) && res.data.me.length === 1 && typeof res.data.me[0].uid === 'string'\n}","tryCatchPattern":null,"preventionTips":["Never hand-edit ACL data (dgraph.xid nodes) in Ratel","After restores/imports, always re-run or verify ACL bootstrap","Alert on any query returning more than one node with dgraph.xid == 'groot'"],"tags":["acl","dgraph","groot","bootstrap"],"backgroundTag":"acl-bootstrap-failure","analyzedSha":"759e242be62c91f8d084da06ad0c8d21256d9c07","analyzedAt":"2026-09-01T14:42:12.034Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}