eyaltoledano/claude-task-master · error · TaskMasterError
CONFIG_ERROR
CONFIG_ERROR
Error message
'Failed to save configuration'
What it means
ConfigPersistenceService.saveConfig writes config.json atomically (temp file + rename) and throws TaskMasterError with code CONFIG_ERROR when any step — mkdir, writeFile, or rename — fails. details.configPath identifies the target file; the original error is attached as cause.
Source
Thrown at packages/tm-core/src/modules/config/services/config-persistence.service.ts:72
}
// Ensure directory exists
const configDir = path.dirname(this.localConfigPath);
await fs.mkdir(configDir, { recursive: true });
const jsonContent = JSON.stringify(config, null, 2);
if (atomic) {
// Atomic write: write to temp file then rename
const tempPath = `${this.localConfigPath}.tmp`;
await fs.writeFile(tempPath, jsonContent, 'utf-8');
await fs.rename(tempPath, this.localConfigPath);
} else {
// Direct write
await fs.writeFile(this.localConfigPath, jsonContent, 'utf-8');
}
} catch (error) {
throw new TaskMasterError(
'Failed to save configuration',
ERROR_CODES.CONFIG_ERROR,
{ configPath: this.localConfigPath },
error as Error
);
}
}
/**
* Create a backup of the current configuration
*/
private async createBackup(): Promise<string> {
try {
await fs.mkdir(this.backupDir, { recursive: true });
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const backupPath = path.join(this.backupDir, `config-${timestamp}.json`);
View on GitHub (pinned to c0c98d367c)
Solutions
- Check free disk space and file permissions on details.configPath and its directory, then retry
- Ensure the target is a regular writable file, not a directory or symlink loop
- Close tools that may lock the file (editors, antivirus, sync clients) or exclude the config dir from syncing
- Run the process as a user with write access to the config location, or point config at a writable path
Example fix
// before
await persistence.saveConfig(config); // throws on read-only dir
// after
try {
await persistence.saveConfig(config);
} catch (e) {
if (e instanceof TaskMasterError && e.code === 'CONFIG_ERROR') {
await fs.chmod(path.dirname(e.details.configPath), 0o755); // fix perms
await persistence.saveConfig(config); // retry
} else { throw e; }
} Defensive patterns
Strategy: retry
Validate before calling
import { access, constants } from 'fs/promises';
await access(path.dirname(configPath), constants.W_OK); // throws early if dir not writable
const st = await stat(configPath).catch(() => null);
if (st && !st.isFile()) throw new Error(`${configPath} is not a regular file`); Type guard
function isConfigWriteError(e: unknown): e is TaskMasterError & { details: { configPath: string } } {
return e instanceof TaskMasterError && e.code === 'CONFIG_ERROR'
&& typeof (e.details as any)?.configPath === 'string';
} Try / catch
try {
await persistence.saveConfig(config);
} catch (e) {
if (isConfigWriteError(e)) {
await fixPermissionsOrFreeDisk(e.details.configPath);
await persistence.saveConfig(config); // retry once
} else { throw e; }
} Prevention
- Ensure the config directory exists and is writable before first save
- Exclude the config dir from antivirus/backup/sync tools that lock files during rename
- Monitor disk space/quota in environments that write config frequently
- Never replace config.json with a directory or symlink
When it happens
Trigger: Calling saveConfig when the config directory doesn't exist and can't be created, the disk is full, permissions deny writing (EACCES/EPERM), the target is read-only, or the rename fails because the target is locked (EBUSY/EISDIR on Windows).
Common situations: Read-only filesystem or container without write access to home dir; disk quota exceeded; antivirus/backup tools locking the temp file during rename; running as a user without permission to ~/.task-master; config.json replaced by a directory.
Related errors
- CONFIG_ERROR
- CONFIG_ERROR
- Failed to read file ${filePath}: ${error.message}
- Failed to read ${filePath} for modification: ${err.message}
- Failed to create directory ${dirPath}: ${error.message}
AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29).
Data as JSON: /api/errors/e683d710406d5bcf.
Report an issue: GitHub.