eyaltoledano/claude-task-master · error

INVALID_SUBTASK_ID

INVALID_SUBTASK_ID

Error message

Subtask ID cannot be empty.

What it means

The subtask `id` argument must be a non-empty string. updateSubtaskByIdDirect rejects null, undefined, non-string values, or whitespace-only strings with INVALID_SUBTASK_ID before any storage lookup. In API storage IDs like 'HAM-2611' are valid; in file storage the form 'parentId.subtaskId' (e.g. '5.2') is expected — but either way it must be a non-empty string.

Source

Thrown at mcp-server/src/core/direct-functions/update-subtask-by-id.js:61

		if (!tasksJsonPath) {
			const errorMessage = 'tasksJsonPath is required but was not provided.';
			logWrapper.error(errorMessage);
			return {
				success: false,
				error: { code: 'MISSING_ARGUMENT', message: errorMessage }
			};
		}

		// Basic validation - ID must be present
		// In API storage, subtask IDs like "HAM-2611" are valid (no dot required)
		// In file storage, subtask IDs must be in format "parentId.subtaskId"
		// The core function handles storage-specific validation
		if (!id || typeof id !== 'string' || !id.trim()) {
			const errorMessage = 'Subtask ID cannot be empty.';
			logWrapper.error(errorMessage);
			return {
				success: false,
				error: { code: 'INVALID_SUBTASK_ID', message: errorMessage }
			};
		}

		// At least prompt or metadata is required (validated in MCP tool layer)
		if (!prompt && !metadata) {
			const errorMessage =
				'No prompt or metadata specified. Please provide information to append or metadata to update.';
			logWrapper.error(errorMessage);
			return {
				success: false,
				error: { code: 'MISSING_PROMPT', message: errorMessage }
			};
		}

		const subtaskIdStr = String(id).trim();

		// Use the provided path
		const tasksPath = tasksJsonPath;

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Pass the subtask ID as a string: id: '5.2' (file storage) or the ticket ID like 'HAM-2611' (API storage).
  2. Verify the value is defined at the call site — log or inspect arguments before the tool call.
  3. If the ID comes from another tool's output, confirm that lookup succeeded and copy the exact ID.

Example fix

// before
const id = 5.2; // number — wrong
// after
const id = '5.2'; // dotted string
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof id !== 'string' || !id.trim()) throw new Error('subtask id must be a non-empty string');
// file storage additionally expects 'parentId.subtaskId'
if (/\d+\.\d+/.test(id) === false && !/^[A-Z]+-\d+/.test(id)) {
  console.warn('ID does not look like "5.2" or "HAM-2611"');
}

Type guard

function isSubtaskId(v) { return typeof v === 'string' && v.trim().length > 0 && (/^\d+\.\d+$/.test(v.trim()) || /^[A-Z]+-\d+(\.\d+)?$/.test(v.trim())); }

Prevention

When it happens

Trigger: Passing id: null/undefined, a number (5.2 as float loses the dotted-string semantics), an empty string, or ' ' when calling the update-subtask-by-id tool.

Common situations: JavaScript callers passing numeric subtask IDs (5.02 collapses to 5.2); template strings interpolating an undefined variable into ''; agents hallucinating an ID after a failed task lookup.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


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