ruvnet/ruflo · error

Node ${agentId} not found

Error message

Node ${agentId} not found

What it means

updateNode() mutates a node looked up by agentId in nodeIndex; an unknown id throws before any field is applied. The index is keyed by the bare agentId, not by the generated node id (node_ plus agentId). Removal, including auto-rebalance evictions, deletes the entry, so updates racing a removal will miss.

Source

Thrown at v3/@claude-flow/swarm/src/topology-manager.ts:173

    for (const partition of this.state.partitions) {
      partition.nodes = partition.nodes.filter(n => n !== agentId);
      if (partition.leader === agentId) {
        partition.leader = partition.nodes[0] || '';
      }
    }

    this.emit('node.removed', { agentId });

    // Trigger rebalance if needed
    if (this.config.autoRebalance) {
      await this.rebalance();
    }
  }

  async updateNode(agentId: string, updates: Partial<TopologyNode>): Promise<void> {
    const node = this.nodeIndex.get(agentId);
    if (!node) {
      throw new Error(`Node ${agentId} not found`);
    }

    // Apply updates
    if (updates.role !== undefined) node.role = updates.role;
    if (updates.status !== undefined) node.status = updates.status;
    if (updates.connections !== undefined) {
      node.connections = updates.connections;
      this.adjacencyList.set(agentId, new Set(updates.connections));
    }
    if (updates.metadata !== undefined) {
      node.metadata = { ...node.metadata, ...updates.metadata };
    }

    this.emit('node.updated', { agentId, updates });
  }

  getLeader(): string | undefined {
    return this.state.leader;

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Confirm you pass the bare agentId (not the node_-prefixed id) to updateNode
  2. Check the node exists via getState().nodes before updating
  3. If the node was removed, re-add it with addNode instead of updating

Example fix

// before
await topology.updateNode(`node_${agentId}`, { status: 'active' }); // throws: index is keyed by agentId

// after
await topology.updateNode(agentId, { status: 'active' });
Defensive patterns

Strategy: validation

Validate before calling

function findNode(topology: TopologyManager, agentId: string): TopologyNode | undefined {
  return topology.getState().nodes.find(n => n.agentId === agentId);
}

if (!findNode(topology, agentId)) {
  await topology.addNode(agentId, 'worker'); // node was evicted: rejoin
}
await topology.updateNode(agentId, { status: 'active' });

Type guard

function nodeExists(topology: TopologyManager, agentId: string): boolean {
  return topology.getState().nodes.some(n => n.agentId === agentId);
}

Try / catch

try {
  await topology.updateNode(agentId, updates);
} catch (err) {
  if (err instanceof Error && err.message.endsWith(`Node ${agentId} not found`)) {
    await topology.addNode(agentId, 'worker');
    return topology.updateNode(agentId, updates);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling updateNode(agentId, ...) for an agent never added, already removed, or using the prefixed node.id instead of the bare agentId; status pings that race removeNode during rebalance.

Common situations: Confusing node.id with agentId in logs or scripts; heartbeats arriving after a node was evicted; typos in scripted agent ids.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/68ad93e6dd68488b. Report an issue: GitHub.