eyaltoledano/claude-task-master · error

DIRECTORY_CREATE_FAILED

DIRECTORY_CREATE_FAILED

Error message

Failed to create output directory ${outputDir}: ${error.message}

What it means

Before parsing, parsePRDDirect ensures the output directory (dirname of the resolved tasks.json output path) exists, creating it recursively with fs.mkdirSync (parse-prd.js:101-114). If directory creation fails — permissions, read-only filesystem, path is actually a file — it returns DIRECTORY_CREATE_FAILED with the OS error message.

Source

Thrown at mcp-server/src/core/direct-functions/parse-prd.js:112

		logWrapper.error(errorMsg);
		return {
			success: false,
			error: { code: 'FILE_NOT_FOUND', message: errorMsg }
		};
	}

	const outputDir = path.dirname(outputPath);
	try {
		if (!fs.existsSync(outputDir)) {
			logWrapper.info(`Creating output directory: ${outputDir}`);
			fs.mkdirSync(outputDir, { recursive: true });
		}
	} catch (error) {
		const errorMsg = `Failed to create output directory ${outputDir}: ${error.message}`;
		logWrapper.error(errorMsg);
		return {
			success: false,
			error: { code: 'DIRECTORY_CREATE_FAILED', message: errorMsg }
		};
	}

	let numTasks = getDefaultNumTasks(projectRoot);
	if (numTasksArg) {
		numTasks =
			typeof numTasksArg === 'string' ? parseInt(numTasksArg, 10) : numTasksArg;
		if (Number.isNaN(numTasks) || numTasks < 0) {
			// Ensure positive number
			numTasks = getDefaultNumTasks(projectRoot); // Fallback to default if parsing fails or invalid
			logWrapper.warn(
				`Invalid numTasks value: ${numTasksArg}. Using default: ${numTasks}`
			);
		}
	}

	if (append) {
		logWrapper.info('Append mode enabled.');

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Read the OS error in the message: EACCES/EPERM → fix permissions; ENOTDIR/EEXIST → a file occupies part of the path; EROFS → remount writable.
  2. Verify the `output` argument: it should be the tasks.json file path (its dirname will be created), not a path colliding with an existing file.
  3. Ensure the MCP server process user can write to projectRoot (chown/chmod or run with correct user).
  4. Pre-create the directory manually (mkdir -p) and confirm it succeeds before retrying.

Example fix

// before
await parsePRDDirect({ projectRoot: '/proj', input: prd, output: '/proj/.taskmaster/tasks' }, log);
// tasks exists as a FILE -> DIRECTORY_CREATE_FAILED

// after
await parsePRDDirect({ projectRoot: '/proj', input: prd, output: '/proj/.taskmaster/tasks/tasks.json' }, log);
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('fs');
const path = require('path');
function outputDirCreatable(outputPath) {
  const dir = path.dirname(outputPath);
  if (fs.existsSync(dir) && !fs.statSync(dir).isDirectory()) return false;
  try { fs.accessSync(path.dirname(dir), fs.constants.W_OK); return true; }
  catch { return false; }
}

Try / catch

const result = await parsePRDDirect({ projectRoot, input, output }, log);
if (!result.success && result.error?.code === 'DIRECTORY_CREATE_FAILED') {
  console.error('Cannot create output dir:', result.error.message); // EACCES/ENOTDIR/EROFS
}

Prevention

When it happens

Trigger: The parent path segment of `output` is an existing regular file (mkdirSync hits EEXIST/ENOTDIR); the process lacks write permission on the target directory (EACCES/EPERM); the filesystem is read-only (EROFS, common in containers); disk full (ENOSPC).

Common situations: Output path pointing at an existing file instead of a directory path; running the MCP server as a user without write access to the project; Docker volumes mounted read-only; a `output` value that accidentally overrode the tasks.json file path with a directory-style value.

Related errors


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