eyaltoledano/claude-task-master · error

TASK_NOT_FOUND

TASK_NOT_FOUND

Error message

Task with ID ${taskId} not found

What it means

After loading tasks and searching for the requested ID, expandTaskDirect returns this TASK_NOT_FOUND error when no task in the file matches taskId. The taskId in the message is the parsed integer, so IDs as strings vs numbers are normalized before lookup.

Source

Thrown at mcp-server/src/core/direct-functions/expand-task.js:130

			return {
				success: false,
				error: {
					code: 'INVALID_TASKS_FILE',
					message: `No valid tasks found in ${tasksPath}. readJSON returned: ${JSON.stringify(data)}`
				}
			};
		}

		// Find the specific task
		log.info(`[expandTaskDirect] Searching for task ID ${taskId} in data`);
		const task = data.tasks.find((t) => t.id === taskId);
		log.info(`[expandTaskDirect] Task found: ${task ? 'Yes' : 'No'}`);

		if (!task) {
			return {
				success: false,
				error: {
					code: 'TASK_NOT_FOUND',
					message: `Task with ID ${taskId} not found`
				}
			};
		}

		// Check if task is completed
		if (task.status === 'done' || task.status === 'completed') {
			return {
				success: false,
				error: {
					code: 'TASK_COMPLETED',
					message: `Task ${taskId} is already marked as ${task.status} and cannot be expanded`
				}
			};
		}

		// Check for existing subtasks and force flag
		const hasExistingSubtasks = task.subtasks && task.subtasks.length > 0;

View on GitHub (pinned to c0c98d367c)

Solutions

  1. List tasks (list/read tasks.json) and confirm the exact ID, then retry with a valid one.
  2. If targeting a subtask, use the subtask-specific expansion parameters/tool instead of ID '3.1'.
  3. Re-run parse-prd or check for re-numbering if IDs shifted after regeneration.
  4. Guard the call: verify the task exists in the file before invoking expand.

Example fix

// before
await expandTaskDirect({ tasksJsonPath, id: '12' }); // only 9 tasks exist
// after
const { tasks } = JSON.parse(fs.readFileSync(tasksJsonPath, 'utf8'));
if (tasks.some(t => t.id === 12)) {
  await expandTaskDirect({ tasksJsonPath, id: '12' });
}
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('fs');
function taskExists(p, id) {
  const data = JSON.parse(fs.readFileSync(p, 'utf8'));
  return Array.isArray(data.tasks) && data.tasks.some(t => t.id === parseInt(id, 10));
}
if (!taskExists(tasksJsonPath, id)) {
  throw new Error(`Task ${id} not in ${tasksJsonPath}; refresh the task list first`);
}

Type guard

function findTask(data, id) {
  if (!data || !Array.isArray(data.tasks)) return undefined;
  return data.tasks.find(t => t.id === parseInt(id, 10));
}

Try / catch

const res = await expandTaskDirect(args);
if (!res.success && res.error?.code === 'TASK_NOT_FOUND') {
  // re-list tasks and retry with a valid ID instead of failing the workflow
  const tasks = listTaskIds(tasksJsonPath);
  console.warn(`ID ${args.id} missing. Available: ${tasks.join(', ')}`);
}

Prevention

When it happens

Trigger: Calling expand_task with an ID that does not exist in tasks.json (typo, out of range, task deleted), or passing a subtask ID ('3.1') to a lookup that only searches top-level tasks, or stale ID references after re-numbering from parse-prd.

Common situations: Regenerating tasks invalidates previously known IDs; agent-supplied IDs hallucinated by the LLM; trying to expand a completed/removed task; referencing subtask IDs through the top-level task tool.

Related errors


AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29). Data as JSON: /api/errors/5f8f3af3c573e12f. Report an issue: GitHub.