bmad-code-org/BMAD-METHOD · error · Error
${label} exists but is not a directory: ${dirPath}
Error message
${label} exists but is not a directory: ${dirPath} What it means
Thrown by ensureWritableDir when the target path already exists but is not a directory (stat resolves and isDirectory() is false). Used to validate writable directories like the project root and the _bmad subdirectories (config, core, scripts, custom) before install proceeds.
Source
Thrown at tools/installer/core/install-paths.js:110
async function assertReadableFile(filePath, label) {
const stat = await fs.stat(filePath).catch(() => null);
if (!stat) {
throw new Error(`${label} does not exist: ${filePath}`);
}
if (!stat.isFile()) {
throw new Error(`${label} is not a file: ${filePath}`);
}
try {
await fs.access(filePath, fs.constants.R_OK);
} catch {
throw new Error(`${label} is not readable: ${filePath}`);
}
}
async function ensureWritableDir(dirPath, label) {
const stat = await fs.stat(dirPath).catch(() => null);
if (stat && !stat.isDirectory()) {
throw new Error(`${label} exists but is not a directory: ${dirPath}`);
}
try {
await fs.ensureDir(dirPath);
} catch (error) {
if (error.code === 'EACCES') {
throw new Error(`${label}: permission denied creating directory: ${dirPath}`);
}
if (error.code === 'ENOSPC') {
throw new Error(`${label}: no space left on device: ${dirPath}`);
}
throw new Error(`${label}: cannot create directory: ${dirPath} (${error.message})`);
}
try {
await fs.access(dirPath, fs.constants.R_OK | fs.constants.W_OK);
} catch {
throw new Error(`${label} is not writable: ${dirPath}`);View on GitHub (pinned to b70486b9bd)
Solutions
- Inspect the path: `ls -la <dirPath>`.
- Point `--directory` at a real (or non-existent) directory path.
- Remove the conflicting file if it is safe to do so.
Defensive patterns
Strategy: validation
Validate before calling
const stat = await fs.stat(dirPath).catch(() => null);
if (stat && !stat.isDirectory()) {
throw new Error(`Refusing to install: ${dirPath} is a file, not a directory`);
} Try / catch
try {
await ensureWritableDir(dirPath, label);
} catch (error) {
if (error.message.includes('exists but is not a directory')) { /* pick another target */ }
throw error;
} Prevention
- Pass --directory a path that is (or will be) a directory.
- Clean up stray files left by aborted installs.
When it happens
Trigger: InstallPaths.create() runs ensureWritableDir on the project root or one of the bmad subdirectories, and a file already occupies that exact path.
Common situations: The user points `--directory` at a path where a regular file exists (e.g. `bmad install --directory ./myfile.txt`), or a previous failed install left a file where a directory is now expected.
Related errors
- ${label} does not exist: ${dirPath}
- ${label} is not a directory: ${dirPath}
- ${label} is not readable: ${dirPath}
- ${label} does not exist: ${filePath}
- ${label} is not a file: ${filePath}
AI-assisted analysis of bmad-code-org/BMAD-METHOD@b70486b9bd (2026-08-13).
Data as JSON: /api/errors/985356bb2c7972b4.
Report an issue: GitHub.