ruvnet/ruflo · error
Rollout not found: ${rolloutId}
Error message
Rollout not found: ${rolloutId} What it means
EvolutionPipeline.advanceStage() moves a staged rollout to its next stage or auto-rolls back when divergence exceeds the stage threshold. Rollouts live in the in-memory `rollouts` Map and their IDs are only minted by stage(), so this error means the rolloutId was never issued by this pipeline instance (or was lost to a restart). It is checked before the in-progress status check, so an unknown ID always throws rather than returning a reason object.
Source
Thrown at v3/@claude-flow/guidance/src/evolution.ts:505
}
// ==========================================================================
// Advance Stage
// ==========================================================================
/**
* Advance to the next rollout stage or auto-rollback.
*
* If `stageMetrics.divergence` exceeds the current stage's threshold,
* the rollout is automatically rolled back.
*/
advanceStage(
rolloutId: string,
stageMetrics: Record<string, number>,
): { advanced: boolean; rolledBack: boolean; reason: string } {
const rollout = this.rollouts.get(rolloutId);
if (!rollout) {
throw new Error(`Rollout not found: ${rolloutId}`);
}
if (rollout.status !== 'in-progress') {
return {
advanced: false,
rolledBack: false,
reason: `Rollout is ${rollout.status}, not in-progress`,
};
}
const current = rollout.stages[rollout.currentStage];
const now = Date.now();
// Record metrics on the current stage
current.metrics = { ...stageMetrics };
// Check divergence against threshold
const divergence = stageMetrics.divergence ?? 0;View on GitHub (pinned to fa13ee4ad6)
Solutions
- Use the rolloutId captured from `const rollout = pipeline.stage(proposalId)`
- Guard with `if (!pipeline.getRollout(rolloutId)) return;` before advancing
- Re-create the rollout (stage again on a live proposal) after a restart
- Keep stage()/advanceStage() calls on one long-lived pipeline instance
Example fix
// before
const r = pipeline.advanceStage(savedRolloutId, metrics); // throws after restart
// after
const existing = pipeline.getRollout(savedRolloutId);
if (existing) {
const r = pipeline.advanceStage(savedRolloutId, metrics);
} else {
const rollout = pipeline.stage(liveProposalId); // re-stage, then advance
const r = pipeline.advanceStage(rollout.rolloutId, metrics);
} Defensive patterns
Strategy: validation
Validate before calling
if (pipeline.getRollout(rolloutId) === undefined) {
// rollout unknown to this instance — re-stage before advancing
} Try / catch
try {
const r = pipeline.advanceStage(rolloutId, metrics);
} catch (err) {
if (err instanceof Error && err.message.startsWith('Rollout not found')) {
// restart wiped rollouts — re-stage the proposal
} else throw err;
} Prevention
- Capture the rolloutId from stage() and pass it unchanged to advanceStage()
- Keep canary/advance jobs on the same long-lived pipeline instance
- Check getRollout() before deferred advance jobs run
When it happens
Trigger: Calling `advanceStage(rolloutId, metrics)` with an ID not returned by stage(); pipeline restarted between staging and advancing (Map lost); advancing on a different pipeline instance than the one that staged; copying the rolloutId from logs with a typo.
Common situations: Long-running canary jobs that sleep between stages and survive a redeploy; metrics-collection workers calling advanceStage from a separate process; replaying operational runbooks against a fresh pipeline.
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} not found
- EvolutionPipeline requires an explicit signingKey — hardcode
- hexToBytes: odd-length hex string
- 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/80e2b5e1860891ae.
Report an issue: GitHub.