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

  1. Open the file at details.configPath and fix JSON syntax errors (run it through a JSON validator)
  2. Fix file permissions/ownership so the current process can read it
  3. If irrecoverable, back up and delete the corrupt config.json — loadLocalConfig then returns null and defaults are used
  4. 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

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


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