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
- Confirm you pass the bare agentId (not the node_-prefixed id) to updateNode
- Check the node exists via getState().nodes before updating
- 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
- Key external bookkeeping by bare agentId, never by the generated node.id
- Heartbeat loops should treat not found as a rejoin signal, not a bug
- Log both agentId and node.id in topology events to catch key confusion early
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
- hexToBytes: odd-length hex string
- SSRF guard: only HTTPS URLs are permitted, got ${parsed.prot
- SSRF guard: private/loopback host rejected — ${host}
- SSRF guard: invalid URL — ${rawUrl}
- SSRF guard: only HTTPS URLs are permitted, got ${parsed.prot
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/68ad93e6dd68488b.
Report an issue: GitHub.