dgraph-io/dgraph · critical

Multiple groot users found

Error message

Multiple groot users found

What it means

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.

Source

Thrown at edgraph/access.go:590

	type userQryResp struct {
		GrootUser []userNode `json:"grootUser"`
	}

	var grootUserUid string
	var userResp userQryResp
	if err := json.Unmarshal(resp.GetJson(), &userResp); err != nil {
		return errors.Wrap(err, "Couldn't unmarshal response from groot user query")
	}
	if len(userResp.GrootUser) == 0 {
		// no groot user found from query
		// Extract uid of created groot user from mutation
		newUserUidMap := resp.GetUids()
		grootUserUid = newUserUidMap["newuser"]
	} else if len(userResp.GrootUser) == 1 {
		// we found a groot user
		grootUserUid = userResp.GrootUser[0].Uid
	} else {
		return errors.Wrap(err, "Multiple groot users found")
	}

	uid, err := strconv.ParseUint(grootUserUid, 0, 64)
	if err != nil {
		return errors.Wrapf(err, "Error while parsing Uid: %s of groot user", grootUserUid)
	}
	ns, err := x.ExtractNamespace(ctx)
	if err != nil {
		return errors.Wrapf(err, "While upserting user with id %s", x.GrootId)
	}
	x.GrootUid.Store(ns, uid)
	glog.V(2).Infof("Successfully upserted groot account for namespace %d\n", ns)
	return nil
}

// extract the userId, groupIds from the accessJwt in the context
func extractUserAndGroups(ctx context.Context) (*userData, error) {
	accessJwt, err := x.ExtractJwt(ctx)

View on GitHub (pinned to 759e242be6)

Solutions

  1. Inspect the groot user records with a query and delete duplicates so exactly one 'groot' user exists, or recreate the ACL dataset from scratch
  2. Re-bootstrap ACLs on a clean cluster (start with --acl and a fresh Galaxy key) so upsertGroot creates the single groot account
  3. If groot is missing entirely, check earlier errors in upsertGuardianAndGroot (the wrapped err) — the user creation step likely failed
  4. Disable ACL (--acl=false) only as a diagnostic, not a fix, if you don't need ACLs

Example fix

// before: multiple groot users in DB -> error
// after: ensure exactly one groot user via query in Ratel:
//   query { me(func: eq(dgraph.xid, "groot")) { uid } }
// delete extra nodes:
//   upsert { query {...} delete { uid <extra> * * . } }
// then restart with ACL enabled so groot is upserted once
Defensive patterns

Strategy: validation

Validate before calling

// Before relying on ACL bootstrap, verify exactly one groot user exists:
const q = `{ me(func: eq(dgraph.xid, "groot")) { uid } }`
const res = await dg.newTxn().query(q)
const users = res.data.me
if (users.length !== 1) {
  // clean up duplicates or re-bootstrap ACLs before proceeding
  throw new Error(`expected 1 groot user, found ${users.length}`)
}

Type guard

function hasSingleGroot(res) {
  return Array.isArray(res?.data?.me) && res.data.me.length === 1 && typeof res.data.me[0].uid === 'string'
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01). Data as JSON: /api/errors/ef2286700c9cb18a. Report an issue: GitHub.