{"record":{"id":"5225b58f5de2623a","repo":"ruvnet/ruflo","slug":"can-only-queue-pending-tasks","errorCode":null,"errorMessage":"Can only queue pending tasks","messagePattern":"Can only queue pending tasks","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/swarm/src/domain/entities/task.ts","lineNumber":174,"sourceCode":"    return new Date(this._createdAt);\n  }\n  get startedAt(): Date | undefined {\n    return this._startedAt ? new Date(this._startedAt) : undefined;\n  }\n  get completedAt(): Date | undefined {\n    return this._completedAt ? new Date(this._completedAt) : undefined;\n  }\n\n  // ============================================================================\n  // 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   */","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/swarm/src/domain/entities/task.ts#L156-L192","documentation":"Task.queue() transitions a task from 'pending' to 'queued' and only accepts 'pending'. This throw means the task was already queued, assigned, running, or finished — i.e., it entered the pipeline twice.","triggerScenarios":"Double-submission of the same Task entity (two code paths calling queue() on one instance)\nRe-queueing manually instead of using the retry path inside fail() (fail() already resets to 'queued')\nPersistence replay re-applying a queue event to a task rehydrated as 'queued' Producer/consumer both calling queue() on a shared reference","commonSituations":"Duplicate job submissions from retries at the API layer without idempotency keys Event-sourced rebuilds where 'queued' events replay onto already-queued tasks Scheduler restarts re-admitting in-flight tasks","solutions":["Check task.status === 'pending' before queue() (public getter)\nMake submission idempotent upstream with dedupe keys so the same task is never queued twice","For failures/retries, rely on task.fail() (it re-queues automatically up to maxRetries) — never call queue() again yourself","For event replay, skip transitions that don't match the expected pre-state"],"exampleFix":"// before\nsubmit(task); submit(task); // second queue() throws\n\n// after\nfunction submit(task) { if (task.status === 'pending') task.queue(); }","handlingStrategy":"type-guard","validationCode":"if (task.status === 'pending') task.queue();\n// retries: let task.fail() handle re-queueing — never call queue() again manually","typeGuard":"function isQueueable(t) { return t.status === 'pending'; }","tryCatchPattern":"try { task.queue(); }\ncatch (e) {\n  if (e instanceof Error && e.message === 'Can only queue pending tasks') return; // already admitted\n  throw e;\n}","preventionTips":["Dedupe submissions with idempotency keys before they reach the task entity","Follow the pipeline pending -> queued -> assigned -> running -> completed exactly","For failures, rely on fail()'s built-in re-queue instead of re-queueing by hand"],"tags":["task","state-machine","queue","domain-entity","typescript"],"backgroundTag":"state-machine-invalid-transition","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}