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
- 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
- Disable cancel affordances once a task reaches completed/failed
- Sweep shutdown cancellers by status filter, not blanket cancel-all
- Break cancel/complete races with single-flight transitions per task
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
- Can only start assigned tasks
- Can only complete running tasks
- Can only queue pending tasks
- Can only assign queued or pending tasks
- Can only fail running or assigned tasks
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/a7cfb0b47b358004.
Report an issue: GitHub.