eyaltoledano/claude-task-master · error · Error

Subtask ${subtaskId} not found in parent task ${parentId}

Error message

Subtask ${subtaskId} not found in parent task ${parentId}

What it means

After the parent task is located, updateSubtaskStatusInFile searches parentTask.subtasks for a subtask whose id matches the numeric portion after the dot. If no subtask matches, this error is thrown. The parent exists but the specific subtask does not, so the write is aborted.

Source

Thrown at packages/tm-core/src/modules/storage/adapters/file-storage/file-storage.ts:539

		// Find the parent task
		const parentTaskIndex = tasks.findIndex(
			(t) => String(t.id) === String(parentId)
		);

		if (parentTaskIndex === -1) {
			throw new Error(`Parent task ${parentId} not found`);
		}

		const parentTask = tasks[parentTaskIndex];

		// Find the subtask within the parent task
		const subtaskIndex = parentTask.subtasks.findIndex(
			(st) => st.id === subtaskNumericId || String(st.id) === subId
		);

		if (subtaskIndex === -1) {
			throw new Error(
				`Subtask ${subtaskId} not found in parent task ${parentId}`
			);
		}

		const oldStatus = parentTask.subtasks[subtaskIndex].status || 'pending';
		if (oldStatus === newStatus) {
			return {
				success: true,
				oldStatus,
				newStatus,
				taskId: subtaskId
			};
		}

		const now = new Date().toISOString();

		// Update the subtask status
		parentTask.subtasks[subtaskIndex] = {

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Load the parent task and inspect its subtasks array to confirm the subtask ID before updating.
  2. Verify the dotted ID is correct: parentId.subtaskId with a positive integer subtask number.
  3. Check the subtask is not under a different parent or a different tag.
  4. Re-create the subtask if it was deleted and the status update is still needed.

Example fix

// before
await storage.updateTaskStatus('5.9', 'done');
// after
const tasks = await storage.getTasks(tag);
const parent = tasks.find((t) => String(t.id) === '5');
if (!parent?.subtasks?.some((s) => String(s.id) === '9')) {
  throw new Error('Subtask 5.9 does not exist');
}
await storage.updateTaskStatus('5.9', 'done', tag);
Defensive patterns

Strategy: validation

Validate before calling

const tasks = await storage.getTasks(tag);
const [pid, sid] = subtaskId.split('.');
const parent = tasks.find((t) => String(t.id) === pid);
if (!parent?.subtasks?.some((s) => String(s.id) === sid)) {
  throw new Error(`Subtask ${subtaskId} does not exist`);
}

Type guard

function findSubtask(parent: Task, subId: string): Subtask | undefined {
  return parent.subtasks?.find((s) => String(s.id) === subId.trim());
}

Try / catch

try {
  await storage.updateTaskStatus('5.2', 'done', tag);
} catch (err) {
  if (err instanceof Error && /Subtask .* not found in parent/.test(err.message)) {
    console.warn('Subtask missing; refreshing task list');
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: updateTaskStatus('5.9', 'done') where task 5 exists but has no subtask 9; using a stale subtask number after subtasks were renumbered or removed; passing the full subtask object id when only the numeric part is expected; subtask stored under a different parent.

Common situations: Automation referencing subtasks deleted during cleanup; tasks.json edited by hand dropping subtasks; migration between tags where subtask numbering differs; typos in the subtask portion of the dotted ID.

Related errors


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