eyaltoledano/claude-task-master · error

Workflow state file not found at ${this.statePath}

Error message

Workflow state file not found at ${this.statePath}

What it means

WorkflowStateManager.load() reads the workflow state JSON from `this.statePath` and throws a plain Error `Workflow state file not found at <path>` when the read fails with ENOENT. It signals that no workflow state has been persisted yet (or the configured path is wrong), as opposed to a corrupt/unreadable file.

Source

Thrown at packages/tm-core/src/modules/workflow/managers/workflow-state-manager.ts:121

	async exists(): Promise<boolean> {
		try {
			await fs.access(this.statePath);
			return true;
		} catch {
			return false;
		}
	}

	/**
	 * Load workflow state from disk
	 */
	async load(): Promise<WorkflowState> {
		try {
			const content = await fs.readFile(this.statePath, 'utf-8');
			return JSON.parse(content) as WorkflowState;
		} catch (error: any) {
			if (error.code === 'ENOENT') {
				throw new Error(`Workflow state file not found at ${this.statePath}`);
			}
			throw new Error(`Failed to load workflow state: ${error.message}`);
		}
	}

	/**
	 * Save workflow state to disk
	 * Uses steno for atomic writes and automatic queueing of concurrent saves
	 */
	async save(state: WorkflowState): Promise<void> {
		try {
			// Ensure writer is initialized (creates directory if needed)
			await this.ensureWriter();

			// Serialize and validate JSON
			const jsonContent = JSON.stringify(state, null, 2);

			// Validate that the JSON is well-formed by parsing it back

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Call `await stateManager.save(...)` at least once (or the workflow bootstrap that creates it) before load
  2. Verify the process cwd/project root matches where the state file was written; fix statePath configuration
  3. Call `existsSync(statePath)` or try/catch ENOENT and treat as 'no state yet' with a default state instead of crashing

Example fix

// before
const state = await stateManager.load(); // throws on fresh checkout
// after
let state;
try {
  state = await stateManager.load();
} catch (e) {
  if (String(e.message).includes('not found')) state = DEFAULT_WORKFLOW_STATE;
  else throw e;
}
Defensive patterns

Strategy: fallback

Validate before calling

import { existsSync } from 'fs';
if (!existsSync(statePath)) {
  state = DEFAULT_WORKFLOW_STATE; // skip load entirely
} else {
  state = await stateManager.load();
}

Type guard

const isNotFound = (e: unknown) =>
  e instanceof Error && e.message.includes('Workflow state file not found');

Try / catch

let state: WorkflowState;
try {
  state = await stateManager.load();
} catch (e) {
  if (isNotFound(e)) state = DEFAULT_WORKFLOW_STATE;
  else throw e;
}

Prevention

When it happens

Trigger: Calling `await stateManager.load()` before the workflow has ever been saved; statePath configured to a different project/directory than where state was saved; the state file was deleted (clean, git clean, CI fresh checkout).

Common situations: Fresh clone or CI run with no persisted workflow state; switching worktrees/branches where .taskmaster state is gitignored; typo'd project root so statePath points at a non-existent directory.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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