{"record":{"id":"eea299a59b546794","repo":"ruvnet/ruflo","slug":"can-only-fail-running-or-assigned-tasks","errorCode":null,"errorMessage":"Can only fail running or assigned tasks","messagePattern":"Can only fail running or assigned tasks","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/swarm/src/domain/entities/task.ts","lineNumber":218,"sourceCode":"\n  /**\n   * Complete the task successfully\n   */\n  complete(output?: unknown): void {\n    if (this._status !== 'running') {\n      throw new Error('Can only complete running tasks');\n    }\n    this._status = 'completed';\n    this._output = output;\n    this._completedAt = new Date();\n  }\n\n  /**\n   * Mark task as failed\n   */\n  fail(error: string): void {\n    if (this._status !== 'running' && this._status !== 'assigned') {\n      throw new Error('Can only fail running or assigned tasks');\n    }\n    this._error = error;\n    this._retryCount++;\n\n    if (this._retryCount >= this._maxRetries) {\n      this._status = 'failed';\n      this._completedAt = new Date();\n    } else {\n      // Reset for retry\n      this._status = 'queued';\n      this._assignedAgentId = undefined;\n    }\n  }\n\n  /**\n   * Cancel the task\n   */\n  cancel(): void {","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/swarm/src/domain/entities/task.ts#L200-L236","documentation":"Task.fail(error) accepts only 'running' or 'assigned' tasks. It records the error, increments the retry count, and either marks the task 'failed' (retries exhausted) or resets it to 'queued' for another attempt. This throw means fail() was invoked on a task outside those states — e.g., double-failing, or failing pending/finished tasks.","triggerScenarios":"Reporting failure for a task that is still 'pending'/'queued' (failure before assignment/start, e.g., validation errors at intake)\nDouble fail(): the first fail() reset the task to 'queued' (or 'failed'), the second throws\nFailing a task after it was cancelled or already completed\nRetry timer racing a completion: fail() arrives after complete() succeeded","commonSituations":"Intake-time errors routed into task.fail() instead of a pre-queue rejection path\nAt-least-once error events producing duplicate fail() calls\nTimeout supervisors failing tasks whose workers already completed them Reconciliation jobs sweeping and failing every task older than X regardless of status","solutions":["Gate on task.status === 'running' || task.status === 'assigned' before fail()\nFor pre-queue validation errors, reject at the boundary (don't create the task, or use cancel()) instead of fail()\nMake failure reporting idempotent — treat a second fail() on the same attempt as a no-op\nBreak complete/fail races with single-flight state transitions per task (lock or version number)"],"exampleFix":"// before\ncatch (e) { task.fail(e.message); } // throws if already failed/queued/cancelled\n\n// after\ncatch (e) {\n  if (task.status === 'running' || task.status === 'assigned') task.fail(e.message);\n  else log.warn('stale failure for task %s in state %s', task.id, task.status);\n}","handlingStrategy":"type-guard","validationCode":"if (task.status === 'running' || task.status === 'assigned') task.fail(err.message);\nelse if (task.status === 'pending' || task.status === 'queued') task.cancel(); // intake-time error path\nelse logStaleFailure(task);","typeGuard":"function isFailable(t) { return t.status === 'running' || t.status === 'assigned'; }","tryCatchPattern":"try { task.fail(err.message); }\ncatch (e) {\n  if (e instanceof Error && e.message === 'Can only fail running or assigned tasks') return; // stale/dup failure\n  throw e;\n}","preventionTips":["Reject invalid tasks at the boundary (cancel) instead of fail()ing pending ones","Deduplicate error events; a second fail() on the same attempt should be a no-op","Break fail/complete races with per-task locks or version numbers"],"tags":["task","state-machine","error-handling","retry","typescript"],"backgroundTag":"state-machine-invalid-transition","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}