ruvnet/ruflo · error
Can only start assigned tasks
Error message
Can only start assigned tasks
What it means
Task.start() moves a task from 'assigned' to 'running' and refuses anything else. This throw means start() was called on a task that was never assigned, was already started, or already finished — the entity requires the strict pending/queued -> assigned -> running order.
Source
Thrown at v3/@claude-flow/swarm/src/domain/entities/task.ts:195
}
/**
* Assign task to an agent
*/
assign(agentId: string): void {
if (this._status !== 'queued' && this._status !== 'pending') {
throw new Error('Can only assign queued or pending tasks');
}
this._assignedAgentId = agentId;
this._status = 'assigned';
}
/**
* 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();
}
/**View on GitHub (pinned to fa13ee4ad6)
Solutions
- Always assign(agentId) first, then start(); never start an unassigned task
- Check task.status === 'assigned' before start(); treat 'running' as already-in-progress (idempotent skip) Use task claims/leases so only one worker owns a task at a time Discard stale task references after status changes; re-query the task before acting
Example fix
// before
worker.on('task', t => { t.start(); doWork(t); }); // 'pending' task -> throws
// after
worker.on('task', t => {
if (t.status === 'pending' || t.status === 'queued') t.assign(worker.id);
if (t.status === 'assigned') t.start(); // only first worker passes
else return; // already running elsewhere
doWork(t);
}); Defensive patterns
Strategy: type-guard
Validate before calling
if (task.status === 'pending' || task.status === 'queued') task.assign(workerId); // claim first
if (task.status === 'assigned') { task.start(); run(task); }
else skip(); // someone else started it Type guard
function isStartable(t) { return t.status === 'assigned'; } Try / catch
try { task.start(); }
catch (e) {
if (e instanceof Error && e.message === 'Can only start assigned tasks') return; // claimed elsewhere or stale
throw e;
} Prevention
- Use task claims/leases so exactly one worker owns a task
- Never skip assign(); there is no direct pending -> running shortcut
- On worker restart, re-query task status instead of resuming from memory
When it happens
Trigger: Worker pulling a 'pending' task and starting it directly without assign() Double start(): two workers (or a retry) invoking start() on the same task — the second sees 'running' Starting a task after cancel() or after complete() (stale work queue entries) Scheduler calling start() when it meant assign()
Common situations: Queue consumers starting tasks they fetched by query rather than via the assignment flow Crash recovery where a worker restarts and re-starts tasks it already began Duplicate delivery of the same task to two workers
Related errors
- Can only complete running tasks
- Cannot cancel finished 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/d47bbfc117641c75.
Report an issue: GitHub.