{"record":{"id":"60fae6319285acb1","repo":"bmad-code-org/BMAD-METHOD","slug":"label-is-not-a-directory-dirpath","errorCode":null,"errorMessage":"${label} is not a directory: ${dirPath}","messagePattern":"(.+?) is not a directory: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"tools/installer/core/install-paths.js","lineNumber":83,"sourceCode":"  }\n  helpCatalog() {\n    return path.join(this.configDir, 'bmad-help.csv');\n  }\n  moduleDir(name) {\n    return path.join(this.bmadDir, name);\n  }\n  moduleConfig(name) {\n    return path.join(this.bmadDir, name, 'config.yaml');\n  }\n}\n\nasync function assertReadableDir(dirPath, label) {\n  const stat = await fs.stat(dirPath).catch(() => null);\n  if (!stat) {\n    throw new Error(`${label} does not exist: ${dirPath}`);\n  }\n  if (!stat.isDirectory()) {\n    throw new Error(`${label} is not a directory: ${dirPath}`);\n  }\n  try {\n    await fs.access(dirPath, fs.constants.R_OK);\n  } catch {\n    throw new Error(`${label} is not readable: ${dirPath}`);\n  }\n}\n\nasync 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);","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/bmad-code-org/BMAD-METHOD/blob/b70486b9bdcb0a404d329e2a763b57964e7f1360/tools/installer/core/install-paths.js#L65-L101","documentation":"Thrown by assertReadableDir when the path exists (stat succeeds) but stat.isDirectory() is false — a regular file or special file sits where a directory is required. Distinct from the not-exist and not-readable cases so the user knows the path is the wrong type.","triggerScenarios":"InstallPaths.create() validates a directory path that is occupied by a file. E.g. srcDir resolves to a path where a file named like the expected directory exists.","commonSituations":"A file was accidentally created with the same name as an expected directory, a symlink points to a file instead of a directory, or a packaging step shipped a file where a directory was expected.","solutions":["Inspect the path with `ls -la <dirPath>` to confirm what type of node occupies it.","Remove or rename the offending file so the expected directory can be used.","Re-extract/reinstall the package so directory structure is correct."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const stat = await fs.stat(dirPath).catch(() => null);\nif (stat && !stat.isDirectory()) {\n  // surface a friendly error before the installer throws\n}","typeGuard":null,"tryCatchPattern":"try {\n  await assertReadableDir(dirPath, label);\n} catch (error) {\n  if (error.message.includes('is not a directory')) { /* wrong type */ }\n  throw error;\n}","preventionTips":["Confirm expected paths are directories before install.","Avoid creating files whose names collide with required directories."],"tags":["filesystem","precondition","installer"],"backgroundTag":null,"analyzedSha":"b70486b9bdcb0a404d329e2a763b57964e7f1360","analyzedAt":"2026-08-13T01:21:12.247Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}