eyaltoledano/claude-task-master · error · TaskMasterError
CONFIG_ERROR
CONFIG_ERROR
Error message
'Failed to load local configuration'
What it means
ConfigLoaderService.loadLocalConfig reads the local config.json and returns null when the file simply doesn't exist (ENOENT). For any other read/parse failure it wraps the error in a TaskMasterError with code CONFIG_ERROR and the configPath in details. The original error is attached as the cause.
Source
Thrown at packages/tm-core/src/modules/config/services/config-loader.service.ts:97
},
version: DEFAULT_CONFIG_VALUES.VERSION
};
}
/**
* Load local project configuration
*/
async loadLocalConfig(): Promise<PartialConfiguration | null> {
try {
const configData = await fs.readFile(this.localConfigPath, 'utf-8');
return JSON.parse(configData);
} catch (error: any) {
if (error.code === 'ENOENT') {
// File doesn't exist, return null
this.logger.debug('No local config.json found, using defaults');
return null;
}
throw new TaskMasterError(
'Failed to load local configuration',
ERROR_CODES.CONFIG_ERROR,
{ configPath: this.localConfigPath },
error
);
}
}
/**
* Load global user configuration
* @future-implementation Full implementation pending
*/
async loadGlobalConfig(): Promise<PartialConfiguration | null> {
// TODO: Implement in future PR
// For now, return null to indicate no global config
return null;
// Future implementation:View on GitHub (pinned to c0c98d367c)
Solutions
- Open the file at details.configPath and fix JSON syntax errors (run it through a JSON validator)
- Fix file permissions/ownership so the current process can read it
- If irrecoverable, back up and delete the corrupt config.json — loadLocalConfig then returns null and defaults are used
- Recreate the file with `tm` init/context commands rather than by hand
Example fix
// before
const cfg = await loader.loadLocalConfig(); // throws CONFIG_ERROR on corrupt JSON
// after
let cfg;
try {
cfg = await loader.loadLocalConfig();
} catch (e) {
if (e instanceof TaskMasterError && e.code === 'CONFIG_ERROR') {
await fs.rename(e.details.configPath, `${e.details.configPath}.bak`); // quarantine
cfg = null; // fall back to defaults
} else { throw e; }
} Defensive patterns
Strategy: try-catch
Validate before calling
import { stat } from 'fs/promises';
try {
const s = await stat(configPath);
if (!s.isFile()) throw new Error(`${configPath} is not a regular file`);
JSON.parse(await readFile(configPath, 'utf-8')); // detect corrupt JSON early
} catch (err) {
if ((err as NodeJS.ErrnoException).code === 'ENOENT') { /* fine: defaults will be used */ }
else throw err;
} Type guard
function isConfigError(e: unknown): e is TaskMasterError {
return e instanceof TaskMasterError && e.code === 'CONFIG_ERROR';
} Try / catch
try {
cfg = await loader.loadLocalConfig();
} catch (e) {
if (isConfigError(e)) {
// e.details.configPath: quarantine/repair file, then fall back to defaults
cfg = null;
} else { throw e; }
} Prevention
- Don't hand-edit config.json; use tm commands that validate on write
- Validate JSON with a linter after any manual edit
- Keep only one process/tool owning the config file to avoid partial writes
- Back up the file before bulk changes; a null return (missing) is fine, CONFIG_ERROR means it exists but is broken
When it happens
Trigger: Calling loadLocalConfig (directly or via localConfig/result getters) when config.json exists but cannot be read or parsed — permission denied, invalid JSON, EISDIR, EACCES, or a disk error.
Common situations: Hand-edited config.json with a JSON syntax error; file locked by another process on Windows; permission changes after switching users or running under a service account; config.json is actually a directory; partial write from a crashed process.
Related errors
- CONFIG_ERROR
- CONFIG_ERROR
- Invalid or missing tasks file at ${tasksPath}
- No valid tasks found in ${tasksPath}.
- Failed to get brief creation URL
AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29).
Data as JSON: /api/errors/f2932687e80be0db.
Report an issue: GitHub.