eyaltoledano/claude-task-master · error

Task ID is required

Error message

Task ID is required

What it means

The storage layer's validateTask guard runs before storage operations and requires a Task to have id, title, description, and status. This error is thrown when a task object with a missing/empty `id` is passed to a create/update/delete storage method, preventing corrupt or unaddressable records from entering storage.

Source

Thrown at packages/tm-core/src/common/interfaces/storage.interface.ts:453

	 * @param originalPath - Original file path
	 * @returns Backup file path with timestamp
	 */
	protected generateBackupPath(originalPath: string): string {
		const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
		const parts = originalPath.split('.');
		const extension = parts.pop();
		const baseName = parts.join('.');
		return `${baseName}.backup.${timestamp}.${extension}`;
	}

	/**
	 * Utility method to validate task data before storage operations
	 * @param task - Task to validate
	 * @throws Error if task is invalid
	 */
	protected validateTask(task: Task): void {
		if (!task.id) {
			throw new Error('Task ID is required');
		}
		if (!task.title) {
			throw new Error('Task title is required');
		}
		if (!task.description) {
			throw new Error('Task description is required');
		}
		if (!task.status) {
			throw new Error('Task status is required');
		}
	}

	/**
	 * Utility method to sanitize tag names for file system safety
	 * @param tag - Tag name to sanitize
	 * @returns Sanitized tag name
	 */
	protected sanitizeTag(tag: string): string {

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Assign a valid id before the storage call (generate one via your id scheme, e.g. numeric or string id).
  2. Validate/normalize incoming payloads to ensure `id` is present before mapping to Task.
  3. Check the deserialization path (JSON parse/mapper) isn't omitting the id field.
  4. Update Task fixtures/factories to always include id.

Example fix

// before
await storage.saveTask({ title: 'Fix bug', description: '...', status: 'pending' });
// after
await storage.saveTask({ id: nextId(), title: 'Fix bug', description: '...', status: 'pending' });
Defensive patterns

Strategy: validation

Validate before calling

function assertTaskBasics(t) { if (!t.id) throw new Error('Task must have an id before storage'); if (!t.title) throw new Error('Task must have a title'); if (!t.description) throw new Error('Task must have a description'); if (!t.status) throw new Error('Task must have a status'); }

Type guard

function isStorableTask(t) { return typeof t?.id === 'string' && t.id.length > 0 || (typeof t?.id === 'number' && Number.isFinite(t.id)); }

Try / catch

try { await storage.saveTask(task); } catch (e) { if (e.message === 'Task ID is required') { throw new InvalidTaskError('id', task); } throw e; }

Prevention

When it happens

Trigger: Calling storage.save/update with a Task built without an id (undefined, null, or empty string); deserialization dropping the id field; constructing a new Task manually and forgetting to assign the id.

Common situations: Mapping external data (imports, API payloads) into Task objects without normalizing ids; schema migrations leaving legacy rows/objects without ids; tests constructing partial Task fixtures.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


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