ruvnet/ruflo · error · Error

Workflow cannot be resumed

Error message

Workflow cannot be resumed

What it means

Thrown by MaestroPlugin.resumeWorkflow() when the given workflowId is not present in the plugin's in-memory workflow registry, or when the workflow's status is anything other than 'paused'. Only workflows explicitly parked via pauseWorkflow() (which checkpoints state and sets status='paused') are resumable; resume simply re-enters executeWorkflow(). It is a lifecycle state-machine guard, not a crash: running, completed, failed, or unknown workflows all refuse to resume.

Source

Thrown at v3/@claude-flow/shared/src/plugins/official/maestro-plugin.ts:251

  /**
   * Pause a workflow
   */
  pauseWorkflow(workflowId: string): boolean {
    const workflow = this.workflows.get(workflowId);
    if (!workflow || workflow.status !== 'running') return false;

    this.checkpointWorkflow(workflow);
    workflow.status = 'paused';
    return true;
  }

  /**
   * Resume a paused workflow
   */
  async resumeWorkflow(workflowId: string): Promise<OrchestrationResult> {
    const workflow = this.workflows.get(workflowId);
    if (!workflow || workflow.status !== 'paused') {
      throw new Error('Workflow cannot be resumed');
    }

    // Restore from checkpoint and continue
    return this.executeWorkflow(workflowId);
  }

  /**
   * Get workflow status
   */
  getWorkflow(workflowId: string): Workflow | undefined {
    return this.workflows.get(workflowId);
  }

  /**
   * List all workflows
   */
  listWorkflows(): Workflow[] {
    return Array.from(this.workflows.values());

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Call and await pauseWorkflow(workflowId) first — only status 'paused' can be resumed.
  2. Guard the call: const wf = maestro.getWorkflow(workflowId); proceed only when wf && wf.status === 'paused'.
  3. If getWorkflow(id) is undefined, the id is wrong or in-memory state was lost — re-create the workflow instead of resuming.
  4. For terminal statuses ('completed', 'failed'), start a new workflow run rather than resuming the old one.

Example fix

// before
await maestro.resumeWorkflow(workflowId); // throws unless status === 'paused'

// after
const wf = maestro.getWorkflow(workflowId);
if (!wf) throw new Error(`unknown workflow ${workflowId}`);
if (wf.status !== 'paused') {
  await maestro.pauseWorkflow(workflowId);
}
const result = await maestro.resumeWorkflow(workflowId);
Defensive patterns

Strategy: validation

Validate before calling

const wf = maestro.getWorkflow(workflowId);
const resumable = !!wf && wf.status === 'paused';
if (!resumable) {
  // pause the workflow first, or start a new run — do not call resumeWorkflow
}

Type guard

function isResumableWorkflow(wf: Workflow | undefined): wf is Workflow & { status: 'paused' } {
  return wf !== undefined && wf.status === 'paused';
}

Try / catch

try {
  await maestro.resumeWorkflow(workflowId);
} catch (e) {
  if (e instanceof Error && e.message === 'Workflow cannot be resumed') {
    const wf = maestro.getWorkflow(workflowId);
    if (!wf) { /* unknown id: re-create the workflow */ }
    else if (wf.status === 'completed' || wf.status === 'failed') { /* start a new run */ }
    else { /* still running: wait, then pause + resume */ }
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling maestro.resumeWorkflow(id) while the workflow is still 'running' (pauseWorkflow never called or not yet awaited); resuming a 'completed' or 'failed' workflow; passing a workflowId that was never created with this plugin instance; calling resume after a process restart, since the workflows map is in-memory and the id no longer resolves.

Common situations: A resume button or API endpoint wired straight to resumeWorkflow without a status check; user clicks resume after the run already finished; plugin instance recreated on deploy/restart losing in-memory state; race where resume fires before pause completes.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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