eyaltoledano/claude-task-master · error · Error

Failed to create directory ${dirPath}: ${error.message}

Error message

Failed to create directory ${dirPath}: ${error.message}

What it means

ensureDir() wraps fs.mkdir(dirPath, { recursive: true }) failures into 'Failed to create directory <path>: <reason>'. Recursive mkdir rarely fails on missing parents, so this almost always means an OS-level obstruction: a non-directory exists at the path (or an ancestor), or permission is denied.

Source

Thrown at packages/tm-core/src/modules/storage/adapters/file-storage/file-operations.ts:232

	async getStats(filePath: string) {
		return fs.stat(filePath);
	}

	/**
	 * Read directory contents
	 */
	async readDir(dirPath: string): Promise<string[]> {
		return fs.readdir(dirPath);
	}

	/**
	 * Create directory recursively
	 */
	async ensureDir(dirPath: string): Promise<void> {
		try {
			await fs.mkdir(dirPath, { recursive: true });
		} catch (error: any) {
			throw new Error(
				`Failed to create directory ${dirPath}: ${error.message}`
			);
		}
	}

	/**
	 * Delete file
	 */
	async deleteFile(filePath: string): Promise<void> {
		try {
			await fs.unlink(filePath);
		} catch (error: any) {
			if (error.code !== 'ENOENT') {
				throw new Error(`Failed to delete file ${filePath}: ${error.message}`);
			}
		}
	}

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Check the OS error in the message: if EEXIST/ENOTDIR, remove or rename the file occupying the path; if EACCES, fix parent-directory permissions.
  2. Verify the storage root configuration (project path / HOME) points to a writable location.
  3. If the filesystem is read-only (Docker/CI), mount a writable volume for the .taskmaster directory.
  4. Free disk space if the error indicates ENOSPC.

Example fix

// before
ls -la ~/ | grep .taskmaster   # -rw-r--r-- .taskmaster (a file)
// after
rm ~/ .taskmaster 2>/dev/null; rm ~/.taskmaster && mkdir ~/.taskmaster
Defensive patterns

Strategy: validation

Validate before calling

import { stat } from 'fs/promises';
import path from 'path';
export async function canCreateDir(dirPath: string): Promise<boolean> {
  try {
    const s = await stat(dirPath);
    return s.isDirectory(); // exists and IS a directory
  } catch (err: any) {
    if (err.code === 'ENOENT') {
      const parent = path.dirname(dirPath);
      try { await access(parent, constants.W_OK); return true; } catch { return false; }
    }
    return false;
  }
}

Try / catch

try {
  await fileOps.ensureDir(dirPath);
} catch (err: any) {
  if (err.message.startsWith('Failed to create directory')) {
    console.error(`Check path ${dirPath}: a file may occupy it or perms deny write (${err.message})`);
    throw err;
  }
  throw err;
}

Prevention

When it happens

Trigger: ensureDir callers (initialize, saveTasks, logActivity) invoked when the target path or an ancestor exists as a regular file, the filesystem is read-only, or the user lacks write permission on the parent directory.

Common situations: A file named like the directory (e.g. a file literally called '.taskmaster') blocks creation; running in a read-only container image or read-only mount; HOME misconfigured so the storage root resolves to an unwritable path; disk full (ENOSPC).

Related errors


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