dgraph-io/dgraph · critical

REUSE_RAFTID: Duplicate Raft ID %d to removed member: %+v

Error message

REUSE_RAFTID: Duplicate Raft ID %d to removed member: %+v

What it means

Zero keeps a list of removed members precisely so their Raft IDs are never reused. If a node connects claiming an ID that matches an entry in membership state's Removed list (with a non-zero group), Zero rejects the connection: reusing a Raft ID corrupts consensus history. The node must be provisioned with a fresh ID or the stale removed entry cleared deliberately.

Source

Thrown at dgraph/cmd/zero/zero.go:549

	}

	if m.ClusterInfoOnly {
		// This request only wants to access the membership state, and nothing else. Most likely
		// from our clients.
		cs := &pb.ConnectionState{
			State:      ms,
			MaxPending: s.orc.MaxPending(),
		}
		return cs, err
	}
	if m.Addr == "" {
		return &emptyConnectionState, errors.Errorf("NO_ADDR: No address provided: %+v", m)
	}

	for _, member := range ms.Removed {
		// It is not recommended to reuse RAFT ids.
		if member.GroupId != 0 && m.Id == member.Id {
			return &emptyConnectionState, errors.Errorf(
				"REUSE_RAFTID: Duplicate Raft ID %d to removed member: %+v", m.Id, member)
		}
	}

	numberOfNodes := len(ms.Zeros)
	for _, group := range ms.Groups {
		for _, member := range group.Members {
			switch {
			case member.Addr == m.Addr && m.Id == 0:
				glog.Infof("Found a member with the same address. Returning: %+v", member)
				conn.GetPools().Connect(m.Addr, s.tlsClientConfig)
				return &pb.ConnectionState{
					State:  ms,
					Member: member,
				}, nil

			case member.Addr == m.Addr && member.Id != m.Id:
				// Same address. Different Id. If Id is zero, then it might be trying to connect for

View on GitHub (pinned to 759e242be6)

Solutions

  1. Delete the node's Raft/wal state (the p directory) so it starts with a brand-new Raft ID, then reconnect.
  2. Provision the node with a unique, unused --raft "id=<n>" value.
  3. If the removal was a mistake and the old node is truly gone, restart Zero cluster state or manually account for the removed member before reusing the ID.
  4. Never clone data directories between nodes; ensure each node gets fresh Raft state.

Example fix

// before (reused id from removed member)
dgraph alpha --my=a1:7080 --zero=z1:5080 --raft "id=2"

// after (fresh raft state)
rm -rf p && dgraph alpha --my=a1:7080 --zero=z1:5080
Defensive patterns

Strategy: validation

Validate before calling

state := fetchZeroState("http://zero:6080/state")
for _, rm := range state.Removed {
    if rm.Id == myRaftID {
        return fmt.Errorf("raft id %d belongs to a removed member; wipe p/ or pick a new id", myRaftID)
    }
}

Try / catch

_, err := zc.Connect(ctx, m)
if err != nil && strings.Contains(err.Error(), "REUSE_RAFTID") {
    return fmt.Errorf("never reuse a removed member's raft id; wipe raft state and rejoin: %w", err)
}

Prevention

When it happens

Trigger: Calling Connect with m.Id equal to the Id of a member in ms.Removed (member.GroupId != 0); typically re-adding a wiped alpha that kept its old Raft state/p_id, or misconfigured --raft "id" flag colliding with a removed node.

Common situations: Rebuilding a node from a snapshot that preserved the Raft ID; cloning a VM/container image with an existing p/raft state; restoring postings dir without clearing raft groups; CI reuse of fixed raft IDs.

Related errors


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