eyaltoledano/claude-task-master · error · MoveTaskError

INVALID_SOURCE_TAG

INVALID_SOURCE_TAG

Error message

Source tag "${sourceTag}" not found or invalid

What it means

This MoveTaskError with code INVALID_SOURCE_TAG is thrown by validateMove when the source tag is missing from tasks.json, is not an object, or lacks a valid tasks array (rawData[sourceTag].tasks must be an Array). Tag-scoped moves require an existing, well-formed source tag section; the library will not move tasks out of a nonexistent or malformed tag.

Source

Thrown at scripts/modules/task-manager/move-task.js:640

 */
async function validateMove(tasksPath, taskIds, sourceTag, targetTag, context) {
	const { projectRoot } = context;

	// Read the raw data without tag resolution to preserve tagged structure
	let rawData = readJSON(tasksPath, projectRoot, sourceTag);

	// Handle the case where readJSON returns resolved data with _rawTaggedData
	if (rawData && rawData._rawTaggedData) {
		rawData = rawData._rawTaggedData;
	}

	// Validate source tag exists
	if (
		!rawData ||
		!rawData[sourceTag] ||
		!Array.isArray(rawData[sourceTag].tasks)
	) {
		throw new MoveTaskError(
			MOVE_ERROR_CODES.INVALID_SOURCE_TAG,
			`Source tag "${sourceTag}" not found or invalid`
		);
	}

	// Create target tag if it doesn't exist
	if (!rawData[targetTag]) {
		rawData[targetTag] = { tasks: [] };
		log('info', `Created new tag "${targetTag}"`);
	}

	// Normalize all IDs to strings once for consistent comparison
	const normalizedSearchIds = taskIds.map((id) => String(id));

	const sourceTasks = rawData[sourceTag].tasks.filter((t) => {
		const normalizedTaskId = String(t.id);
		return normalizedSearchIds.includes(normalizedTaskId);
	});

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Run the tag list command (or inspect tasks.json) to confirm the exact source tag name and spelling.
  2. Create the source tag first if it does not exist, add/keep tasks in it, then move.
  3. Match casing exactly when passing the tag.
  4. Validate the JSON structure: ensure rawData[sourceTag] is an object with a tasks array before calling.
  5. Update automation/config to the renamed tag.

Example fix

// before
moveTasksBetweenTags(tasksPath, ['3'], 'backlog', 'in-progress'); // tag 'backlog' missing
// after
const data = readJSON(tasksPath);
if (!data.backlog || !Array.isArray(data.backlog.tasks)) {
  throw new Error('Tag "backlog" missing; run: task-master tags');
}
moveTasksBetweenTags(tasksPath, ['3'], 'backlog', 'in-progress');
Defensive patterns

Strategy: validation

Validate before calling

const data = JSON.parse(fs.readFileSync(tasksPath, 'utf8'));
if (!data || typeof data[sourceTag] !== 'object' || !Array.isArray(data[sourceTag]?.tasks)) {
  throw new Error(`Source tag "${sourceTag}" missing or malformed.`);
}

Type guard

function isValidTagSection(data, tag) {
  return Boolean(data) && typeof data[tag] === 'object' &&
    data[tag] !== null && Array.isArray(data[tag].tasks);
}

Try / catch

try {
  await moveTasksBetweenTags(tasksPath, ids, sourceTag, targetTag);
} catch (e) {
  if (e.code === 'INVALID_SOURCE_TAG') {
    console.error(`Tag "${sourceTag}" invalid; available: ${Object.keys(readTags())}`);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling move-task across tags where --from/tag name is misspelled; the tag was never created (tags are only created via tag creation or by creating the first task in it); tasks.json was hand-edited so the tag lost its tasks array; casing mismatch ('Backlog' vs 'backlog').

Common situations: Scripting cross-tag migrations with hardcoded tag names after a rename; fresh repo where the tag exists in docs but not in tasks.json; manual JSON edits stripping the tasks key; case-sensitivity surprises.

Related errors


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