{"record":{"id":"341e53bc1230c84e","repo":"ruvnet/ruflo","slug":"can-only-assign-queued-or-pending-tasks","errorCode":null,"errorMessage":"Can only assign queued or pending tasks","messagePattern":"Can only assign queued or pending tasks","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/swarm/src/domain/entities/task.ts","lineNumber":184,"sourceCode":"  // Business Logic\n  // ============================================================================\n\n  /**\n   * Queue the task for execution\n   */\n  queue(): void {\n    if (this._status !== 'pending') {\n      throw new Error('Can only queue pending tasks');\n    }\n    this._status = 'queued';\n  }\n\n  /**\n   * Assign task to an agent\n   */\n  assign(agentId: string): void {\n    if (this._status !== 'queued' && this._status !== 'pending') {\n      throw new Error('Can only assign queued or pending tasks');\n    }\n    this._assignedAgentId = agentId;\n    this._status = 'assigned';\n  }\n\n  /**\n   * Start task execution\n   */\n  start(): void {\n    if (this._status !== 'assigned') {\n      throw new Error('Can only start assigned tasks');\n    }\n    this._status = 'running';\n    this._startedAt = new Date();\n  }\n\n  /**\n   * Complete the task successfully","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/swarm/src/domain/entities/task.ts#L166-L202","documentation":"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.","triggerScenarios":"Assigning a task twice (status already 'assigned')\nAssigning a completed/failed/cancelled task (stale dispatcher decisions)\nAssigning a running task to a different agent to 'steal' it — the entity does not support work stealing\nRace between a scheduler assign and a worker that already started the task","commonSituations":"Multiple schedulers/dispatchers active over the same task list Failover logic that reassigns tasks without first failing/cancelling them\nRecovery scans assigning every task in the store regardless of status Duplicate dispatch messages (at-least-once delivery)","solutions":["Gate on task.status === 'queued' || task.status === 'pending' before assign()\nTo reassign an already-assigned task, first task.cancel() (or let fail() reset it) so it returns to a legal pre-state\nRun a single dispatcher or use per-task locking to prevent concurrent assignment decisions\nDrop stale assignment decisions produced before a state change (compare statuses, last-write-wins with versioning)"],"exampleFix":"// before\nfunction dispatch(task, agentId) { task.assign(agentId); } // throws on reassigned/running\n\n// after\nfunction dispatch(task, agentId) {\n  if (task.status === 'queued' || task.status === 'pending') { task.assign(agentId); return true; }\n  return false; // skip stale decisions\n}","handlingStrategy":"type-guard","validationCode":"if (task.status === 'queued' || task.status === 'pending') {\n  task.assign(agentId);\n} else {\n  handleStaleDecision(task); // already owned/started/finished\n}","typeGuard":"function isAssignable(t) { return t.status === 'queued' || t.status === 'pending'; }","tryCatchPattern":"try { task.assign(agentId); }\ncatch (e) {\n  if (e instanceof Error && e.message === 'Can only assign queued or pending tasks') return; // stale dispatch\n  throw e;\n}","preventionTips":["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"],"tags":["task","task-assignment","state-machine","typescript"],"backgroundTag":"state-machine-invalid-transition","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}