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
- Read the OS error in the message: EACCES/EPERM → fix permissions; ENOTDIR/EEXIST → a file occupies part of the path; EROFS → remount writable.
- 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.
- Ensure the MCP server process user can write to projectRoot (chown/chmod or run with correct user).
- 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
- Point `output` at the tasks.json file path, not a path occupied by an existing file.
- Run the MCP server with a user that has write access to projectRoot.
- Avoid read-only volume mounts for the output location.
- Pre-create the directory with mkdir -p and check it succeeds.
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
- Failed to create directory ${dirPath}: ${error.message}
- CONFIG_ERROR
- Failed to read file ${filePath}: ${error.message}
- Failed to read ${filePath} for modification: ${err.message}
- Failed to delete file ${filePath}: ${error.message}
AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29).
Data as JSON: /api/errors/5fcf345653a7472a.
Report an issue: GitHub.