eyaltoledano/claude-task-master · warning

TASK_COMPLETED

TASK_COMPLETED

Error message

Task ${taskId} is already marked as ${task.status} and cannot be expanded

What it means

expandTaskDirect refuses to expand a task that is already marked 'done' or 'completed'. Task Master treats expansion as a planning operation only valid for open work; expanding a finished task would generate meaningless subtasks. The MCP tool returns a structured {success:false, error:{code:'TASK_COMPLETED'}} result instead of throwing.

Source

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

		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;
		if (hasExistingSubtasks && !forceFlag) {
			log.info(
				`Task ${taskId} already has ${task.subtasks.length} subtasks. Use --force to overwrite.`
			);
			return {
				success: true,
				data: {
					message: `Task ${taskId} already has subtasks. Expansion skipped.`,
					task,
					subtasksAdded: 0,
					hasExistingSubtasks

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Check task.status before calling expand_task and skip tasks marked done/completed
  2. Pick a different open task ID to expand
  3. If the task truly needs rework, set its status back to 'pending' (or via update_task_status) then re-run expand_task
  4. If subtasks already exist and you intended regeneration, use force:true instead — but that still requires a non-completed task

Example fix

// before
await mcp.call('expand_task', { projectId, taskId: '5' }); // task 5 is done
// after
const task = await mcp.call('get_task', { projectId, taskId: '5' });
if (task.status !== 'done' && task.status !== 'completed') {
  await mcp.call('expand_task', { projectId, taskId: '5' });
}
Defensive patterns

Strategy: validation

Validate before calling

const task = await getTask(projectRoot, taskId);
if (task.status === 'done' || task.status === 'completed') {
  throw new Error(`Skip expand_task: task ${taskId} is ${task.status}`);
}

Type guard

function isExpandable(task) {
  return typeof task === 'object' && task !== null &&
    task.status !== 'done' && task.status !== 'completed';
}

Try / catch

try {
  const res = await callTool('expand_task', { taskId, projectRoot });
  if (!res.success && res.error?.code === 'TASK_COMPLETED') {
    console.warn(`Task ${taskId} already completed; skipping expansion`);
  }
} catch (e) { console.error(e.message); }

Prevention

When it happens

Trigger: Calling the expand_task MCP tool with a taskId whose status is 'done' or 'completed' in tasks.json (and no early bypass).

Common situations: AI agents iterating a task list after finishing work and forgetting to skip completed IDs; stale client caches pointing at a task another session closed; replaying an old expand call after the task was marked complete.

Related errors


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