{"record":{"id":"dd544d15e666f074","repo":"ruvnet/ruflo","slug":"task-taskid-has-exceeded-max-retries","errorCode":null,"errorMessage":"Task ${taskId} has exceeded max retries","messagePattern":"Task (.+?) has exceeded max retries","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/shared/src/core/orchestrator/task-manager.ts","lineNumber":248,"sourceCode":"    this.metrics.cancelledTasks++;\n\n    this.eventBus.emit(SystemEventTypes.TASK_CANCELLED, {\n      taskId,\n      reason: reason ?? 'User requested',\n    });\n  }\n\n  async retryTask(taskId: string): Promise<void> {\n    const task = this.tasks.get(taskId);\n    if (!task) {\n      throw new Error(`Task not found: ${taskId}`);\n    }\n\n    const retryCount = (task.metadata?.retryCount as number) ?? 0;\n    const maxRetries = (task.metadata?.maxRetries as number) ?? 3;\n\n    if (retryCount >= maxRetries) {\n      throw new Error(`Task ${taskId} has exceeded max retries`);\n    }\n\n    task.status = 'pending';\n    task.assignedAgent = undefined;\n    task.startedAt = undefined;\n    task.completedAt = undefined;\n    task.error = undefined;\n    task.metadata = {\n      ...task.metadata,\n      retryCount: retryCount + 1,\n    };\n\n    await this.queue.enqueue(task);\n\n    this.eventBus.emit(SystemEventTypes.TASK_RETRY, {\n      taskId,\n      attempt: retryCount + 1,\n      maxAttempts: maxRetries,","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/shared/src/core/orchestrator/task-manager.ts#L230-L266","documentation":"retryTask() reads retryCount and maxRetries from task.metadata (maxRetries defaults to 3) and refuses to reset a task whose retryCount has already reached the ceiling. The task stays in its failed state, forcing the caller to either create a fresh task or raise the budget. This prevents infinite retry loops on permanently failing tasks.","triggerScenarios":"Calling retryTask(taskId) on a task whose metadata.retryCount has been incremented to metadata.maxRetries (default 3) by previous retries; a task created with an explicitly small metadata.maxRetries (e.g. 1) failing twice.","commonSituations":"Automated retry loops exhausting the default 3 attempts on flaky external dependencies; maxRetries set too low at createTask() time for the workload's real failure rate; code assuming retryTask always succeeds.","solutions":["Create a replacement task via createTask() with fresh metadata (retryCount: 0) instead of retrying the exhausted one","If failures are genuinely transient, set a higher metadata.maxRetries when creating the task","Before retrying, compare taskManager.getTask(taskId).metadata.retryCount against maxRetries"],"exampleFix":"// before\nawait taskManager.retryTask(taskId); // throws: exceeded max retries\n\n// after\nconst task = taskManager.getTask(taskId)!;\nconst { retryCount = 0, maxRetries = 3 } = task.metadata ?? {};\nif (retryCount < maxRetries) {\n  await taskManager.retryTask(taskId);\n} else {\n  await taskManager.createTask({ ...originalParams, metadata: { ...task.metadata, retryCount: 0 } });\n}","handlingStrategy":"validation","validationCode":"const task = taskManager.getTask(taskId);\nconst retryCount = (task?.metadata?.retryCount as number) ?? 0;\nconst maxRetries = (task?.metadata?.maxRetries as number) ?? 3;\nif (retryCount < maxRetries) {\n  await taskManager.retryTask(taskId);\n} else {\n  await taskManager.createTask({ ...originalParams, metadata: { retryCount: 0, maxRetries } });\n}","typeGuard":"function canRetry(task: ITask | undefined): boolean {\n  const retryCount = (task?.metadata?.retryCount as number) ?? 0;\n  const maxRetries = (task?.metadata?.maxRetries as number) ?? 3;\n  return !!task && task.status === 'failed' && retryCount < maxRetries;\n}","tryCatchPattern":"try {\n  await taskManager.retryTask(taskId);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('exceeded max retries')) {\n    // budget exhausted: create a fresh task or escalate to a human\n  } else throw e;\n}","preventionTips":["Compare metadata.retryCount against metadata.maxRetries before calling retryTask","Set maxRetries at createTask() based on the dependency's real flakiness","Never loop retryTask() unconditionally — always bound the budget"],"tags":["task","retry","limit","orchestrator"],"backgroundTag":"retry-limit-exceeded","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}