ruvnet/ruflo · error
Can only assign queued or pending tasks
Error message
Can only assign queued or pending tasks
What it means
Task.assign(agentId) accepts only 'queued' or 'pending' statuses. This throw fires when assigning an agent to a task that is already assigned, running, or finished — the entity prevents two owners and post-start assignment.
Source
Thrown at v3/@claude-flow/swarm/src/domain/entities/task.ts:184
// Business Logic
// ============================================================================
/**
* Queue the task for execution
*/
queue(): void {
if (this._status !== 'pending') {
throw new Error('Can only queue pending tasks');
}
this._status = 'queued';
}
/**
* 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 successfullyView on GitHub (pinned to fa13ee4ad6)
Solutions
- Gate on task.status === 'queued' || task.status === 'pending' before assign() To reassign an already-assigned task, first task.cancel() (or let fail() reset it) so it returns to a legal pre-state Run a single dispatcher or use per-task locking to prevent concurrent assignment decisions Drop stale assignment decisions produced before a state change (compare statuses, last-write-wins with versioning)
Example fix
// before
function dispatch(task, agentId) { task.assign(agentId); } // throws on reassigned/running
// after
function dispatch(task, agentId) {
if (task.status === 'queued' || task.status === 'pending') { task.assign(agentId); return true; }
return false; // skip stale decisions
} Defensive patterns
Strategy: type-guard
Validate before calling
if (task.status === 'queued' || task.status === 'pending') {
task.assign(agentId);
} else {
handleStaleDecision(task); // already owned/started/finished
} Type guard
function isAssignable(t) { return t.status === 'queued' || t.status === 'pending'; } Try / catch
try { task.assign(agentId); }
catch (e) {
if (e instanceof Error && e.message === 'Can only assign queued or pending tasks') return; // stale dispatch
throw e;
} Prevention
- Run one dispatcher or lock per task to prevent concurrent assignment
- To reassign, cancel()/fail() first so the task returns to a legal pre-state
- Version task decisions so stale schedulers' assigns are dropped
When it happens
Trigger: Assigning a task twice (status already 'assigned') Assigning a completed/failed/cancelled task (stale dispatcher decisions) Assigning a running task to a different agent to 'steal' it — the entity does not support work stealing Race between a scheduler assign and a worker that already started the task
Common situations: Multiple schedulers/dispatchers active over the same task list Failover logic that reassigns tasks without first failing/cancelling them Recovery scans assigning every task in the store regardless of status Duplicate dispatch messages (at-least-once delivery)
Related errors
- Cannot assign task to terminated agent
- Can only queue pending tasks
- Can only start assigned tasks
- Can only complete running tasks
- Can only fail running or assigned tasks
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/341e53bc1230c84e.
Report an issue: GitHub.