{"record":{"id":"985356bb2c7972b4","repo":"bmad-code-org/BMAD-METHOD","slug":"label-exists-but-is-not-a-directory-dirpath","errorCode":null,"errorMessage":"${label} exists but is not a directory: ${dirPath}","messagePattern":"(.+?) exists but is not a directory: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"tools/installer/core/install-paths.js","lineNumber":110,"sourceCode":"async function assertReadableFile(filePath, label) {\n  const stat = await fs.stat(filePath).catch(() => null);\n  if (!stat) {\n    throw new Error(`${label} does not exist: ${filePath}`);\n  }\n  if (!stat.isFile()) {\n    throw new Error(`${label} is not a file: ${filePath}`);\n  }\n  try {\n    await fs.access(filePath, fs.constants.R_OK);\n  } catch {\n    throw new Error(`${label} is not readable: ${filePath}`);\n  }\n}\n\nasync function ensureWritableDir(dirPath, label) {\n  const stat = await fs.stat(dirPath).catch(() => null);\n  if (stat && !stat.isDirectory()) {\n    throw new Error(`${label} exists but is not a directory: ${dirPath}`);\n  }\n\n  try {\n    await fs.ensureDir(dirPath);\n  } catch (error) {\n    if (error.code === 'EACCES') {\n      throw new Error(`${label}: permission denied creating directory: ${dirPath}`);\n    }\n    if (error.code === 'ENOSPC') {\n      throw new Error(`${label}: no space left on device: ${dirPath}`);\n    }\n    throw new Error(`${label}: cannot create directory: ${dirPath} (${error.message})`);\n  }\n\n  try {\n    await fs.access(dirPath, fs.constants.R_OK | fs.constants.W_OK);\n  } catch {\n    throw new Error(`${label} is not writable: ${dirPath}`);","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/bmad-code-org/BMAD-METHOD/blob/b70486b9bdcb0a404d329e2a763b57964e7f1360/tools/installer/core/install-paths.js#L92-L128","documentation":"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.","triggerScenarios":"InstallPaths.create() runs ensureWritableDir on the project root or one of the bmad subdirectories, and a file already occupies that exact path.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const stat = await fs.stat(dirPath).catch(() => null);\nif (stat && !stat.isDirectory()) {\n  throw new Error(`Refusing to install: ${dirPath} is a file, not a directory`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await ensureWritableDir(dirPath, label);\n} catch (error) {\n  if (error.message.includes('exists but is not a directory')) { /* pick another target */ }\n  throw error;\n}","preventionTips":["Pass --directory a path that is (or will be) a directory.","Clean up stray files left by aborted installs."],"tags":["filesystem","precondition","installer"],"backgroundTag":null,"analyzedSha":"b70486b9bdcb0a404d329e2a763b57964e7f1360","analyzedAt":"2026-08-13T01:21:12.247Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}