eyaltoledano/claude-task-master · error · Error

Invalid subtask ID format: ${subtaskId}. Expected format: pa

Error message

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

What it means

updateSubtaskStatusInFile() expects subtask IDs in the dotted 'parentId.subtaskId' form (e.g. '5.2'). It splits the ID on '.' and requires exactly two segments; anything else — no dot, multiple dots, or empty string — throws this format-validation error before any file access.

Source

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

			oldStatus,
			newStatus,
			taskId: String(taskId)
		};
	}

	/**
	 * Update subtask status within file storage - handles parent status auto-adjustment
	 */
	private async updateSubtaskStatusInFile(
		tasks: Task[],
		subtaskId: string,
		newStatus: TaskStatus,
		tag?: string
	): Promise<UpdateStatusResult> {
		// Parse the subtask ID to get parent ID and subtask ID
		const parts = subtaskId.split('.');
		if (parts.length !== 2) {
			throw new Error(
				`Invalid subtask ID format: ${subtaskId}. Expected format: parentId.subtaskId`
			);
		}

		const [parentId, subIdRaw] = parts;
		const subId = subIdRaw.trim();
		if (!/^\d+$/.test(subId)) {
			throw new Error(
				`Invalid subtask ID: ${subId}. Subtask ID must be a positive integer.`
			);
		}
		const subtaskNumericId = Number(subId);

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

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Normalize the ID to exactly 'parentId.subtaskId' (two integer segments separated by one dot)
  2. Check for deeper nesting: '1.2.3' is invalid here — address only one level
  3. Validate the ID format with a regex before calling
  4. If the ID belongs to a plain task, use the regular task status path instead

Example fix

// before
await storage.updateTaskStatus('1.2.3', 'done'); // invalid: two dots
// after
const id = '1.2'; // correct parentId.subtaskId form
if (!/^\d+\.\d+$/.test(id)) throw new Error(`Bad subtask id: ${id}`);
await storage.updateTaskStatus(id, 'done');
Defensive patterns

Strategy: validation

Validate before calling

function isValidSubtaskId(id: unknown): id is string {
  return typeof id === 'string' && /^\d+\.\d+$/.test(id);
}
// guard: if (!isValidSubtaskId(id)) throw new Error(`Expected parentId.subtaskId, got: ${id}`);

Type guard

function isInvalidSubtaskFormatError(e: unknown): e is Error {
  return e instanceof Error && e.message.startsWith('Invalid subtask ID format:');
}

Try / catch

try {
  await storage.updateTaskStatus(subtaskId, newStatus);
} catch (e) {
  if (isInvalidSubtaskFormatError(e)) {
    // normalize or re-prompt for the ID in 'parentId.subtaskId' form
  } else throw e;
}

Prevention

When it happens

Trigger: Passing a bare task id like '5' to a subtask status update path, an ID with multiple dots such as '5.2.3', an empty or whitespace ID, or routing a non-subtask task ID into updateTaskStatus when it contains dots.

Common situations: Copy-paste errors mixing task and subtask IDs, deep-nested IDs from another tool that supports sub-subtasks (this adapter supports only one level), or user input not normalized before the call.

Related errors


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