ruvnet/ruflo · warning

Cannot cancel finished tasks

Error message

Cannot cancel finished tasks

What it means

Task.cancel() refuses to cancel tasks whose status is 'completed' or 'failed' — terminal states cannot be undone by cancellation. Any other state (pending, queued, assigned, running, even cancelled again) is cancellable. This is the entity protecting result finality.

Source

Thrown at v3/@claude-flow/swarm/src/domain/entities/task.ts:238

    this._error = error;
    this._retryCount++;

    if (this._retryCount >= this._maxRetries) {
      this._status = 'failed';
      this._completedAt = new Date();
    } else {
      // Reset for retry
      this._status = 'queued';
      this._assignedAgentId = undefined;
    }
  }

  /**
   * Cancel the task
   */
  cancel(): void {
    if (this._status === 'completed' || this._status === 'failed') {
      throw new Error('Cannot cancel finished tasks');
    }
    this._status = 'cancelled';
    this._completedAt = new Date();
  }

  /**
   * Check if all dependencies are satisfied
   */
  areDependenciesSatisfied(completedTaskIds: Set<string>): boolean {
    for (const depId of this._dependencies) {
      if (!completedTaskIds.has(depId)) {
        return false;
      }
    }
    return true;
  }

  /**

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Check task.status is not 'completed'/'failed' before cancel() (or make cancel idempotent: 'cancelled' re-cancel is already allowed by this guard, finished is not) Break the completion/cancel race with per-task single-flight transitions Discard stale cancel commands using task version numbers or completion timestamps In UIs, disable cancel once the task reaches a terminal state

Example fix

// before
cancelBtn.onclick = () => task.cancel(); // throws for finished tasks

// after
cancelBtn.onclick = () => {
  if (task.status !== 'completed' && task.status !== 'failed') task.cancel();
};
Defensive patterns

Strategy: type-guard

Validate before calling

const cancellable = (t) => t.status !== 'completed' && t.status !== 'failed';
if (cancellable(task)) task.cancel();

Type guard

function isCancellable(t) { return t.status !== 'completed' && t.status !== 'failed'; }
// note: cancelling an already-'cancelled' task is legal (guard only blocks terminal states)

Try / catch

try { task.cancel(); }
catch (e) {
  if (e instanceof Error && e.message === 'Cannot cancel finished tasks') return; // already final
  throw e;
}

Prevention

When it happens

Trigger: Cancel requests arriving after the task already completed (user hits cancel on a finished job) Timeout supervisor cancelling every in-flight task, including ones that finished a tick earlier Double-cancel of a 'failed' task by both a retry-abort path and a shutdown sweep UI showing stale status so operators cancel finished tasks

Common situations: At-least-once cancellation events without status checks Shutdown routines sweeping the task store and cancelling everything regardless of state Race between a worker's completion and a deadline-triggered cancel

Related errors


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