eyaltoledano/claude-task-master · critical · Error

Failed to load tasks: ${error.message}

Error message

Failed to load tasks: ${error.message}

What it means

loadTasks() reads the single tasks.json file for a tag and enriches tasks with complexity data. ENOENT is treated as 'no tasks yet' (empty array); any other error — JSON corruption, permissions, enrichment failures — is wrapped and rethrown as 'Failed to load tasks'.

Source

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

				if (options.status) {
					tasks = tasks.filter((task) => task.status === options.status);
				}

				// Exclude subtasks if specified
				if (options.excludeSubtasks) {
					tasks = tasks.map((task) => ({
						...task,
						subtasks: []
					}));
				}
			}

			return await this.enrichTasksWithComplexity(tasks, resolvedTag);
		} catch (error: any) {
			if (error.code === 'ENOENT') {
				return []; // File doesn't exist, return empty array
			}
			throw new Error(`Failed to load tasks: ${error.message}`);
		}
	}

	/**
	 * Load a single task by ID from the tasks.json file
	 * Handles both regular tasks and subtasks (with dotted notation like "1.2")
	 */
	async loadTask(taskId: string, tag?: string): Promise<Task | null> {
		const tasks = await this.loadTasks(tag);

		// Check if this is a subtask (contains a dot)
		if (taskId.includes('.')) {
			const [parentId, subtaskId] = taskId.split('.');
			const parentTask = tasks.find((t) => String(t.id) === parentId);

			if (!parentTask || !parentTask.subtasks) {
				return null;
			}

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Inspect error.message in the thrown error for the root cause (parse vs permission)
  2. Validate and repair tasks.json JSON syntax or restore it from version control
  3. Fix permissions: chmod u+r .taskmaster/tasks.json
  4. If the file should not exist yet, delete the corrupt file so ENOENT handling returns an empty task list

Example fix

// before
const tasks = await tmCore.tasks.get(); // throws 'Failed to load tasks: Unexpected token...'
// after: guard the environment first
import { existsSync, readFileSync } from 'fs';
const p = '.taskmaster/tasks.json';
if (existsSync(p)) JSON.parse(readFileSync(p, 'utf8')); // fail fast with a clear parse error
const tasks = await tmCore.tasks.get();
Defensive patterns

Strategy: try-catch

Validate before calling

import { existsSync } from 'fs';
function tasksFileLooksValid(path = '.taskmaster/tasks.json') {
  if (!existsSync(path)) return true; // ENOENT => empty list is fine
  try { const d = JSON.parse(readFileSync(path, 'utf8')); return typeof d === 'object' && d !== null; }
  catch { return false; }
}

Type guard

function isLoadTasksError(e: unknown): e is Error {
  return e instanceof Error && e.message.startsWith('Failed to load tasks:');
}

Try / catch

try {
  const tasks = await storage.loadTasks(tag);
} catch (e) {
  if (isLoadTasksError(e)) {
    // surface the inner cause: e.message.split('Failed to load tasks: ')[1]
    // offer repair/restore UX or restore from backup before retrying
  } else throw e;
}

Prevention

When it happens

Trigger: tasks.json exists but contains invalid JSON, EACCES/EACCES-style permission denial, tasks.json is a directory, or enrichTasksWithComplexity throws while merging complexity report data into the loaded tasks.

Common situations: A partially written tasks.json from a crashed process or interrupted save, a complexity report referencing malformed data, repo cloned without read permissions, or a symlink pointing at a nonexistent/unreadable target.

Related errors


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