eyaltoledano/claude-task-master · error

Invalid subtask ID format: ${subtaskId}. Expected format: "p

Error message

Invalid subtask ID format: ${subtaskId}. Expected format: "parentId.subtaskId"

What it means

removeSubtask only accepts dot-notation subtask IDs like '5.2' (parent.subtask). If the provided subtaskId does not contain a '.', it cannot identify which parent to look under, so this error is thrown.

Source

Thrown at scripts/modules/task-manager/remove-subtask.js:33

	tasksPath,
	subtaskId,
	convertToTask = false,
	generateFiles = false,
	context = {}
) {
	const { projectRoot, tag } = context;
	try {
		log('info', `Removing subtask ${subtaskId}...`);

		// Read the existing tasks with proper context
		const data = readJSON(tasksPath, projectRoot, tag);
		if (!data || !data.tasks) {
			throw new Error(`Invalid or missing tasks file at ${tasksPath}`);
		}

		// Parse the subtask ID (format: "parentId.subtaskId")
		if (!subtaskId.includes('.')) {
			throw new Error(
				`Invalid subtask ID format: ${subtaskId}. Expected format: "parentId.subtaskId"`
			);
		}

		const [parentIdStr, subtaskIdStr] = subtaskId.split('.');
		const parentId = parseInt(parentIdStr, 10);
		const subtaskIdNum = parseInt(subtaskIdStr, 10);

		// Find the parent task
		const parentTask = data.tasks.find((t) => t.id === parentId);
		if (!parentTask) {
			throw new Error(`Parent task with ID ${parentId} not found`);
		}

		// Check if parent has subtasks
		if (!parentTask.subtasks || parentTask.subtasks.length === 0) {
			throw new Error(`Parent task ${parentId} has no subtasks`);
		}

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Use dot-notation: remove-subtask 5.2 instead of 5.
  2. To delete a main task, use remove-task with the plain task ID instead.
  3. Find the correct parent ID with 'task-master list' or show, then rebuild the parent.subtaskId string.

Example fix

// before
task-master remove-subtask --i=7
// after
task-master remove-subtask --i=3.7
Defensive patterns

Strategy: validation

Validate before calling

if (typeof subtaskId !== 'string' || !/^\d+\.\d+$/.test(subtaskId.trim())) {
  throw new Error(`subtaskId must be parent.subtask format, got: ${subtaskId}`);
}

Type guard

function isDotSubtaskId(v: unknown): v is string {
  return typeof v === 'string' && /^\d+\.\d+$/.test(v);
}

Try / catch

try {
  await tmCore.tasks.removeSubtask(tasksPath, subtaskId);
} catch (err) {
  if (err.message.includes('Invalid subtask ID format')) {
    console.error(`'${subtaskId}' is not parent.subtask — use remove-task for main task IDs, or pass e.g. 5.2.`);
  } else throw err;
}

Prevention

When it happens

Trigger: Calling removeSubtask('5') or removeSubtask('subtask-name') — an ID without a dot separator — where a main task ID or non-numeric label was passed instead of a parent.subtask ID.

Common situations: Confusing remove-subtask with remove-task (the latter handles main task IDs), passing a subtask's standalone ID instead of its parent-scoped ID, copying the wrong ID from task listings.

Related errors


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