ruvnet/ruflo · error
Proposal ${proposalId} not found
Error message
Proposal ${proposalId} not found What it means
AdversarialCoordinator.vote() registers a voter's approve/reject decision on a memory proposal held in the in-memory `proposals` Map. It throws when `proposalId` does not match any proposal in this instance. Because state is per-instance and in-memory, the most common root cause is an ID from a previous run or a different coordinator object.
Source
Thrown at v3/@claude-flow/guidance/src/adversarial.ts:696
oldestTimestamp = proposal.timestamp;
oldestId = id;
}
}
if (oldestId) {
this.proposals.delete(oldestId);
}
}
return proposalId;
}
/**
* Vote on a proposal
*/
vote(proposalId: string, voterId: string, approve: boolean): void {
const proposal = this.proposals.get(proposalId);
if (!proposal) {
throw new Error(`Proposal ${proposalId} not found`);
}
if (proposal.resolved) {
throw new Error(`Proposal ${proposalId} already resolved`);
}
proposal.votes.set(voterId, approve);
}
/**
* Resolve a proposal (check if quorum reached)
*/
resolve(proposalId: string): QuorumResult {
const proposal = this.proposals.get(proposalId);
if (!proposal) {
throw new Error(`Proposal ${proposalId} not found`);
}
// Single pass over votes instead of two filter callsView on GitHub (pinned to fa13ee4ad6)
Solutions
- Always use the exact proposalId returned by `propose()`
- Check existence first via the public accessor: `if (coordinator.getProposal(proposalId) === undefined) return;`
- If the coordinator was restarted, re-run propose() to mint a fresh proposal and vote on that
- In multi-instance setups, route all votes for a proposal to the same coordinator instance that created it
Example fix
// before
coordinator.vote(proposalIdFromLastRun, voterId, true); // throws
// after
const proposal = coordinator.getProposal(proposalIdFromLastRun);
if (proposal && !proposal.resolved) {
coordinator.vote(proposalIdFromLastRun, voterId, true);
} Defensive patterns
Strategy: validation
Validate before calling
const proposal = coordinator.getProposal(proposalId);
if (proposal === undefined) {
// unknown to this instance: skip, re-propose, or log
} Try / catch
try {
coordinator.vote(proposalId, voterId, approve);
} catch (err) {
if (err instanceof Error && err.message.endsWith('not found')) {
// stale ID (restart / wrong instance) — drop the vote, do not crash the voter
} else throw err;
} Prevention
- Treat the proposalId returned by propose() as the only valid handle
- Keep propose/vote/resolve on one coordinator instance
- Expect in-memory proposals to vanish on restart and re-propose
When it happens
Trigger: Calling `coordinator.vote(someId, voterId, true)` where someId was never returned by propose(); using a proposalId captured before a process restart (the Map is not persisted); concatenating or truncating the ID string.
Common situations: Service restarted between proposing and voting, dropping all in-memory proposals; multiple coordinator instances (one per worker) with IDs crossing between them; IDs passed through JSON and mangled; voting on already-garbage-collected proposals in long test runs.
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
- Proposal not found: ${proposalId}
- Proposal ${proposalId} already resolved
- SSRF guard: only HTTPS URLs are permitted, got ${parsed.prot
- SSRF guard: private/loopback host rejected — ${host}
- SSRF guard: private/loopback host rejected — ${host}
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/60fba13beb9914b5.
Report an issue: GitHub.