ruvnet/ruflo · error
Proposal not found: ${proposalId}
Error message
Proposal not found: ${proposalId} What it means
EvolutionPipeline.simulate() runs golden traces through baseline and candidate configs for a change proposal stored in the in-memory `proposals` Map, keyed by the ID returned from propose(). It throws when that ID is unknown — typically a stale ID from before a restart or a typo'd/copied value. Simulation is the first lifecycle step that consumes a proposal, so it is often where an invalid ID is discovered.
Source
Thrown at v3/@claude-flow/guidance/src/evolution.ts:319
return proposal;
}
// ==========================================================================
// Simulate
// ==========================================================================
/**
* Run golden traces through both baseline and candidate configs to measure
* divergence. The evaluator is called once per golden trace per config.
*/
simulate(
proposalId: string,
goldenTraces: unknown[],
evaluator: TraceEvaluator,
): SimulationResult {
const proposal = this.proposals.get(proposalId);
if (!proposal) {
throw new Error(`Proposal not found: ${proposalId}`);
}
proposal.status = 'simulating';
// Evaluate each trace against both configs
const baselineResults = goldenTraces.map(t => evaluator(t, 'baseline'));
const candidateResults = goldenTraces.map(t => evaluator(t, 'candidate'));
// Compute composite trace hashes
const baselineTraceHash = this.hashTraceResults(baselineResults.map(r => r.traceHash));
const candidateTraceHash = this.hashTraceResults(candidateResults.map(r => r.traceHash));
// Compute decision diffs
const decisionDiffs: DecisionDiff[] = [];
for (let i = 0; i < goldenTraces.length; i++) {
const bDecisions = baselineResults[i].decisions;
const cDecisions = candidateResults[i].decisions;
const maxLen = Math.max(bDecisions.length, cDecisions.length);View on GitHub (pinned to fa13ee4ad6)
Solutions
- Use the exact proposalId returned by `pipeline.propose(...)`
- Guard with `if (!pipeline.getProposal(proposalId)) return;` before simulating
- Re-propose if the pipeline restarted (state is in-memory)
- Keep the whole propose→simulate→compare→stage→advance lifecycle on one pipeline instance
Example fix
// before
const sim = pipeline.simulate(hardcodedId, traces, evaluator); // throws
// after
if (pipeline.getProposal(hardcodedId)) {
const sim = pipeline.simulate(hardcodedId, traces, evaluator);
} else {
const { proposalId } = pipeline.propose(changes);
const sim = pipeline.simulate(proposalId, traces, evaluator);
} Defensive patterns
Strategy: validation
Validate before calling
if (pipeline.getProposal(proposalId) === undefined) {
// stale/unknown ID — re-propose instead of simulating
} Try / catch
try {
const sim = pipeline.simulate(proposalId, traces, evaluator);
} catch (err) {
if (err instanceof Error && err.message.startsWith('Proposal not found')) {
// restart wiped the Map — re-propose and retry once
} else throw err;
} Prevention
- Store the proposalId from propose() and thread it verbatim
- Keep the propose→simulate→compare→stage lifecycle on one instance
- Assume in-memory proposals do not survive restarts
When it happens
Trigger: Calling `pipeline.simulate(id, traces, evaluator)` with an ID not returned by propose(); pipeline process restarted between propose() and simulate(); ID passed through queues/logs and mangled.
Common situations: Proposing in one service instance and simulating in another; long queues between propose and simulate surviving a redeploy; test code hard-coding IDs from a previous run.
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 ${proposalId} not found
- Rollout not found: ${rolloutId}
- 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/8e7f0d41337e3612.
Report an issue: GitHub.