ruvnet/ruflo · error

Can only complete running tasks

Error message

Can only complete running tasks

What it means

Task.complete(output?) finalizes a task from the 'running' state only. This throw occurs when complete() is called on a task that is pending, queued, assigned, or already finished (completed/failed/cancelled) — including double completion and completion of cancelled work.

Source

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

  }

  /**
   * Start task execution
   */
  start(): void {
    if (this._status !== 'assigned') {
      throw new Error('Can only start assigned tasks');
    }
    this._status = 'running';
    this._startedAt = new Date();
  }

  /**
   * Complete the task successfully
   */
  complete(output?: unknown): void {
    if (this._status !== 'running') {
      throw new Error('Can only complete running tasks');
    }
    this._status = 'completed';
    this._output = output;
    this._completedAt = new Date();
  }

  /**
   * Mark task as failed
   */
  fail(error: string): void {
    if (this._status !== 'running' && this._status !== 'assigned') {
      throw new Error('Can only fail running or assigned tasks');
    }
    this._error = error;
    this._retryCount++;

    if (this._retryCount >= this._maxRetries) {
      this._status = 'failed';

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Make completion idempotent: skip when task.status !== 'running' Guard against races by funnelling complete/fail through one state owner per task (version check or lock) If a cancel arrived first, drop the late completion (or surface it as a 'zombie result' metric) Never skip start() — the pipeline pending/queued -> assigned -> start -> complete must be followed in order

Example fix

// before
await run(task);
task.complete(result); // throws if cancelled/failed/double-completed meanwhile

// after
await run(task);
if (task.status === 'running') task.complete(result);
else reportZombieResult(task.id, result); // cancelled/failed/dup — log, don't throw
Defensive patterns

Strategy: type-guard

Validate before calling

if (task.status === 'running') task.complete(result);
else reportZombieResult(task.id, result); // cancelled/failed/double-complete

Type guard

function isCompletable(t) { return t.status === 'running'; }

Try / catch

try { task.complete(output); }
catch (e) {
  if (e instanceof Error && e.message === 'Can only complete running tasks') return; // idempotent skip
  throw e;
}

Prevention

When it happens

Trigger: Calling complete() twice (second sees 'completed') Completing a task that was cancelled mid-run (status 'cancelled') Completing an 'assigned' task that never had start() called (fast-path shortcuts skipping start) Race: fail() already marked the task 'failed' (retries exhausted) when success arrived late Completion delivered to the wrong task instance after retry-based reassignment

Common situations: At-least-once completion events without idempotency Late success callbacks racing timeouts that already failed the task Workers cancelled (SIGTERM) while their completion message is in flight Optimistic-concurrency violations when two replicas complete the same task

Related errors


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