ruvnet/ruflo · error · Error

Task not found: ${taskId}

Error message

Task not found: ${taskId}

What it means

TaskManager keeps tasks in an in-memory Map keyed by the id returned from createTask(); waitForTask() looks the id up both before starting its polling Promise and again on every poll tick, and throws 'Task not found: <taskId>' when the id is absent. Tasks are never persisted, and a cleanup timer (cleanupOldTasks, default every 60s) deletes finished tasks once their TTL passes. So the error means: this manager never knew the task, or already forgot it.

Source

Thrown at v3/@claude-flow/mcp/src/task-manager.ts:255

  getTasksByState(state: TaskState): TaskResult[] {
    return Array.from(this.tasks.values())
      .filter((task) => task.state === state)
      .map((task) => ({
        taskId: task.id,
        state: task.state,
        progress: task.progress,
        result: task.result,
        error: task.error,
      }));
  }

  /**
   * Wait for task completion
   */
  async waitForTask(taskId: string, timeout?: number): Promise<TaskResult> {
    const task = this.tasks.get(taskId);
    if (!task) {
      throw new Error(`Task not found: ${taskId}`);
    }

    const effectiveTimeout = timeout ?? this.options.taskTimeout;

    return new Promise((resolve, reject) => {
      const checkState = () => {
        const result = this.getTask(taskId);
        if (!result) {
          reject(new Error(`Task not found: ${taskId}`));
          return true;
        }
        if (result.state === 'completed' || result.state === 'failed' || result.state === 'cancelled') {
          resolve(result);
          return true;
        }
        return false;
      };

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Call taskManager.getTask(taskId) first and treat undefined as 'unknown or expired task' instead of waiting
  2. Only wait on ids returned by createTask() on the same TaskManager instance in the same process
  3. Raise taskTtl (and cleanupInterval) in createTaskManager options so waits can outlive cleanup
  4. Subscribe to 'task:completed'/'task:failed' events or await work inside the task executor instead of a long waitForTask

Example fix

// before
const result = await taskManager.waitForTask(taskId, 60_000);

// after
if (!taskManager.getTask(taskId)) {
  throw new Error(`Unknown or expired task: ${taskId}`);
}
const result = await taskManager.waitForTask(taskId, 60_000);
Defensive patterns

Strategy: validation

Validate before calling

const snapshot = taskManager.getTask(taskId);
if (!snapshot) {
  throw new Error(`Task ${taskId} unknown or TTL-expired - not waiting`);
}
const result = await taskManager.waitForTask(taskId, timeout);

Try / catch

try {
  await taskManager.waitForTask(id, timeout);
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Task not found')) {
    // permanent condition (wrong id or cleaned up) - fail fast, never retry
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling waitForTask() with an id from a different TaskManager instance or a previous process run; waiting after cleanupOldTasks() has removed the finished task (wait longer than taskTtl); passing a typo'd or truncated taskId; calling waitForTask() with a hardcoded id in tests against a fresh manager.

Common situations: Producer/consumer split across processes where the consumer only receives the id; integration tests that construct a new TaskManager per case but reuse fixed ids; long waits on short-lived tasks so TTL cleanup wins; MCP server restart between submit and wait.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/54fc966621c7b018. Report an issue: GitHub.