eyaltoledano/claude-task-master · error
Failed to load workflow state: ${error.message}
Error message
Failed to load workflow state: ${error.message} What it means
WorkflowStateManager.load() wraps any non-ENOENT failure (permission denied, invalid JSON from JSON.parse, EACCES, EISDIR) as a plain Error `Failed to load workflow state: <message>`. It distinguishes real load/parse problems from the benign 'file not found' case.
Source
Thrown at packages/tm-core/src/modules/workflow/managers/workflow-state-manager.ts:123
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
try {
JSON.parse(jsonContent);View on GitHub (pinned to c0c98d367c)
Solutions
- Read the embedded original message to decide: JSON SyntaxError → repair/validate the file; EACCES → fix permissions
- Validate the JSON with `JSON.parse(fs.readFileSync(statePath,'utf8'))` manually and fix syntax errors
- Restore the state file from backup or delete it and let the workflow recreate it via save()
- Check ownership/permissions (chmod/chown) and that statePath is a file, not a directory
Example fix
// before
const state = await stateManager.load(); // opaque: Failed to load workflow state: Unexpected token
// after
try {
const state = await stateManager.load();
} catch (e) {
if (e instanceof SyntaxError || String(e.message).includes('Unexpected token')) {
await stateManager.save(DEFAULT_WORKFLOW_STATE); // reset corrupt state
} else throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
import { readFileSync } from 'fs';
try { JSON.parse(readFileSync(statePath, 'utf8')); }
catch (e) { /* corrupt or unreadable — reset or repair before load() */ } Type guard
const isLoadFailure = (e: unknown) =>
e instanceof Error && e.message.startsWith('Failed to load workflow state:'); Try / catch
try {
state = await stateManager.load();
} catch (e) {
if (isLoadFailure(e)) {
await stateManager.save(DEFAULT_WORKFLOW_STATE); // reset corrupt state
state = DEFAULT_WORKFLOW_STATE;
} else throw e;
} Prevention
- Use atomic writes for state (the manager's save uses steno) — never truncate via direct fs writes
- Validate state JSON after manual edits before running the workflow
- Check file permissions/ownership after copying projects between users/containers
- Back up the state file; on parse failure, reset rather than retrying a doomed load
When it happens
Trigger: State file exists but contains invalid JSON (truncated by a crash, hand-edited); read permission denied; statePath is a directory; disk I/O error during fs.readFile.
Common situations: Killed process leaving a half-written state file; user manually editing the JSON and introducing a syntax error; restrictive permissions after copying the project as root or via a container volume mount.
Related errors
- Workflow state file not found at ${this.statePath}
- Failed to save workflow state: ${error.message}
- Failed to create backup: ${error.message}
- Failed to delete workflow state: ${error.message}
- Failed to list backups: ${error.message}
AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29).
Data as JSON: /api/errors/556ee321f752797f.
Report an issue: GitHub.