eyaltoledano/claude-task-master · error · DependencyError

CANNOT_MOVE_SUBTASK

CANNOT_MOVE_SUBTASK

Error message

Cannot move subtask ${taskId} directly between tags.

First promote it to a full task using:
  task-master remove-subtask --id=${taskId} --convert

What it means

A DependencyError with code CANNOT_MOVE_SUBTASK thrown when moving a task between tags with a subtask ID like "5.2". Subtasks cannot be relocated across tags directly; the library requires promoting the subtask to a full task first via remove-subtask --convert. The error message embeds the exact command to run.

Source

Thrown at scripts/modules/dependency-manager.js:1720

		);
	}

	if (!sourceTag || typeof sourceTag !== 'string') {
		throw new DependencyError(
			DEPENDENCY_ERROR_CODES.INVALID_SOURCE_TAG,
			'Source tag must be a valid string'
		);
	}

	if (!targetTag || typeof targetTag !== 'string') {
		throw new DependencyError(
			DEPENDENCY_ERROR_CODES.INVALID_TARGET_TAG,
			'Target tag must be a valid string'
		);
	}

	if (taskId.includes('.')) {
		throw new DependencyError(
			DEPENDENCY_ERROR_CODES.CANNOT_MOVE_SUBTASK,
			`Cannot move subtask ${taskId} directly between tags.

First promote it to a full task using:
  task-master remove-subtask --id=${taskId} --convert`,
			{
				taskId,
				sourceTag,
				targetTag
			}
		);
	}
}

/**
 * Check if a task can be moved with its dependencies
 * @param {string} taskId - Task ID to check
 * @param {string} sourceTag - Source tag name

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Promote the subtask first: task-master remove-subtask --id=5.2 --convert, then move the resulting full task between tags.
  2. If the intent was the parent task, use its plain ID: move-task --id=5 --to=<tag> (moves the whole task).
  3. In scripts, filter IDs containing '.' before calling the move operation.
  4. After conversion, the new task ID appears in the target tag; move it there explicitly.

Example fix

// before
task-master move-task --id=5.2 --to=feature-x
// after
task-master remove-subtask --id=5.2 --convert
task-master move-task --id=<new-task-id> --to=feature-x
Defensive patterns

Strategy: validation

Validate before calling

function assertMovableTaskId(id) {
  if (typeof id !== 'string' || id.includes('.')) {
    throw new Error(`${id} is a subtask; promote it with: task-master remove-subtask --id=${id} --convert before moving between tags`);
  }
}

Type guard

const isFullTaskId = (id) => typeof id === 'string' && /^\d+$/.test(id);

Try / catch

try {
  await moveTask(taskId, targetTag);
} catch (e) {
  if (e.code === 'CANNOT_MOVE_SUBTASK') {
    console.log(e.message); // includes exact convert command
    execSync(`task-master remove-subtask --id=${taskId} --convert`, { stdio: 'inherit' });
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling moveTask/move-task between two tags where taskId contains a dot (e.g. `task-master move-task --from=5.2 --to=tag-b` or programmatic moveTask('5.2', ...) with a targetTag).

Common situations: Reorganizing work across tag contexts (e.g. moving items from 'master' to a feature tag) and picking a subtask ID by mistake, or scripting bulk moves over a task list that includes subtasks.

Related errors


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