eyaltoledano/claude-task-master · error · TaskMasterError
CONFIG_ERROR
CONFIG_ERROR
Error message
'Failed to save runtime state'
What it means
TaskMasterError thrown by RuntimeStateManager.saveState when JSON.stringify + fs.writeFile of the runtime state file fails. It is surfaced through setCurrentTag and updateMetadata, so any tag switch or metadata update that cannot persist the state file fails with this error. The state file path is attached in details.statePath and the fs error as cause.
Source
Thrown at packages/tm-core/src/modules/config/services/runtime-state-manager.service.ts:107
*/
async saveState(): Promise<void> {
const stateDir = path.dirname(this.stateFilePath);
try {
await fs.mkdir(stateDir, { recursive: true });
const stateToSave = {
...this.currentState,
lastUpdated: new Date().toISOString()
};
await fs.writeFile(
this.stateFilePath,
JSON.stringify(stateToSave, null, 2),
'utf-8'
);
} catch (error) {
throw new TaskMasterError(
'Failed to save runtime state',
ERROR_CODES.CONFIG_ERROR,
{ statePath: this.stateFilePath },
error as Error
);
}
}
/**
* Get the currently active tag
*/
getCurrentTag(): string {
return this.currentState.currentTag;
}
/**
* Set the current tag
*/View on GitHub (pinned to c0c98d367c)
Solutions
- Check error.details.statePath and error.cause to identify the exact fs failure
- Create the state file's parent directory (mkdir -p) and ensure write permission for the current user
- If metadata update caused it, verify the metadata object is JSON-serializable (no circular refs, no BigInt)
- Check available disk space (df -h) if the error is ENOSPC
- Avoid running with sudo which can leave root-owned state files; chown them back
Example fix
// before
await stateManager.setCurrentTag('feature-x'); // throws if dir missing
// after
import { mkdirSync } from 'fs';
mkdirSync(path.dirname(statePath), { recursive: true });
await stateManager.setCurrentTag('feature-x'); Defensive patterns
Strategy: validation
Validate before calling
import { accessSync, constants } from 'fs';
const dir = path.dirname(statePath);
try {
accessSync(dir, constants.W_OK);
} catch {
mkdirSync(dir, { recursive: true });
} Type guard
function isSerializable(v: unknown): boolean {
try { JSON.stringify(v); return true; } catch { return false; }
} Try / catch
try {
await stateManager.setCurrentTag(tag);
} catch (e) {
if (e instanceof TaskMasterError && e.details?.statePath) {
console.error(`Cannot write ${e.details.statePath}:`, (e.cause as Error)?.message);
}
// proceed in-memory or abort the tag switch
} Prevention
- Create the state directory (mkdir -p) at app startup
- Ensure metadata passed to updateMetadata is plain JSON-serializable data
- Run as a user owning the project directory; avoid sudo-created root-owned files
- Check disk space before large state writes
- Add the state directory to permissions checks in container/CI setups
When it happens
Trigger: setCurrentTag(tag) or updateMetadata(patch) triggering saveState when the state file's parent directory does not exist, the file/dir is read-only or owned by another user, the disk is full, or stateFilePath points to an invalid location.
Common situations: First run in a fresh project where the .taskmaster directory was gitignored and never created; running the CLI in a Docker container with a read-only volume; permission mismatch after running once with sudo; EACCES on shared CI machines; circular references in metadata causing JSON.stringify to throw.
Related errors
AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29).
Data as JSON: /api/errors/f447a5295fdc8f4d.
Report an issue: GitHub.