ruvnet/ruflo · error · Error

Proposal ${proposalId} not found

Error message

Proposal ${proposalId} not found

What it means

RaftConsensus.vote(proposalId, vote) looks the proposal up in the local proposals map; an id this node never created or received throws 'Proposal ... not found'. Note the adjacent behavior: if the proposal exists but is no longer 'pending', vote() returns silently — so this error specifically means the proposal id is unknown locally, not merely late.

Source

Thrown at v3/@claude-flow/swarm/src/consensus/raft.ts:225

    // Leader votes for itself
    proposal.votes.set(this.node.id, {
      voterId: this.node.id,
      approve: true,
      confidence: 1.0,
      timestamp: new Date(),
    });

    // Replicate to followers
    await this.replicateToFollowers(logEntry);

    return proposal;
  }

  async vote(proposalId: string, vote: ConsensusVote): Promise<void> {
    const proposal = this.proposals.get(proposalId);
    if (!proposal) {
      throw new Error(`Proposal ${proposalId} not found`);
    }

    if (proposal.status !== 'pending') {
      return;
    }

    proposal.votes.set(vote.voterId, vote);

    // Check if we have consensus
    await this.checkConsensus(proposalId);
  }

  async awaitConsensus(proposalId: string): Promise<ConsensusResult> {
    const startTime = Date.now();

    return new Promise((resolve, reject) => {
      const checkInterval = setInterval(() => {
        const proposal = this.proposals.get(proposalId);

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Use the exact proposal object/id returned by propose() when voting.
  2. Guard with a lookup first (e.g. engine.getProposal(proposalId)) and drop or defer votes for unknown ids.
  3. Ensure replication delivers a proposal to a node before it is expected to vote on it.
  4. After a restart, expect unknown-proposal errors for pre-restart proposals — rebuild state or ignore stale votes.

Example fix

// before
await raft.vote(proposalId, vote); // proposalId unknown on this node

// after — guard with a local lookup
if (!engine.getProposal(proposalId)) {
  throw new Error(`proposal ${proposalId} not known locally; await replication`);
}
await engine.vote(proposalId, vote);
Defensive patterns

Strategy: validation

Validate before calling

// guard with the engine-level lookup before voting
if (!engine.getProposal(proposalId)) {
  // unknown locally: drop, or defer until replication delivers it
  return;
}
await engine.vote(proposalId, vote);

Try / catch

try {
  await raft.vote(proposalId, vote);
} catch (e) {
  if (e instanceof Error && /^Proposal .* not found$/.test(e.message)) {
    // unknown proposal on this node: ignore stale votes or await replication
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Voting on a proposal id that was created on another node and never replicated here; a restart wiped the in-memory proposals map while vote messages kept arriving; a mistyped or truncated proposalId; using an engine-level id that differs from the raft-level id.

Common situations: Follower nodes receiving vote requests before the proposal replication reached them; replaying recorded messages after a process restart; string mismatches in ids passed between subsystems.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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