{"record":{"id":"a39667b658d954e0","repo":"bmad-code-org/BMAD-METHOD","slug":"invalid-directory-validation","errorCode":null,"errorMessage":"Invalid directory: ${validation}","messagePattern":"Invalid directory: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"tools/installer/ui.js","lineNumber":252,"sourceCode":"      semver.prerelease(installerPackageJson.version) !== null &&\n      !channelOptions.global &&\n      channelOptions.nextSet.size === 0 &&\n      channelOptions.pins.size === 0\n    ) {\n      channelOptions.global = 'next';\n      await prompts.log.info(\n        'Launched from a prerelease — installing all external modules from main HEAD (next channel). Pass --all-stable or --pin to override.',\n      );\n    }\n\n    // Get directory from options or prompt\n    let confirmedDirectory;\n    if (options.directory) {\n      // Use provided directory from command-line\n      const expandedDir = this.expandUserPath(options.directory);\n      const validation = this.validateDirectorySync(expandedDir);\n      if (validation) {\n        throw new Error(`Invalid directory: ${validation}`);\n      }\n      confirmedDirectory = expandedDir;\n      await prompts.log.info(`Using directory from command-line: ${confirmedDirectory}`);\n    } else {\n      confirmedDirectory = await this.getConfirmedDirectory();\n    }\n\n    const { Installer } = require('./core/installer');\n    const installer = new Installer();\n    const { bmadDir } = await installer.findBmadDir(confirmedDirectory);\n\n    // Check if there's an existing BMAD installation\n    const hasExistingInstall = await fs.pathExists(bmadDir);\n\n    // Track action type (only set if there's an existing installation)\n    let actionType;\n\n    // Only show action menu if there's an existing installation","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/bmad-code-org/BMAD-METHOD/blob/b70486b9bdcb0a404d329e2a763b57964e7f1360/tools/installer/ui.js#L234-L270","documentation":"Thrown from the directory step when validateDirectorySync(expandedDir) returns a non-undefined error string. validateDirectorySync returns messages for: path exists but is not a directory, directory not writable, path doesn't exist and can't be created (parent not writable or no existing parent), or expansion errors re-thrown from expandUserPath (e.g. ~user syntax).","triggerScenarios":"Passing --directory <path> where the path doesn't exist and its nearest existing parent isn't writable; exists but is a file; exists but lacks write permission; or fails tilde expansion (~user syntax).","commonSituations":"Wrong --directory argument; read-only filesystem; pointing at a file; permission denied; using ~otheruser which isn't supported.","solutions":["Pass a directory that exists and is writable, or whose nearest existing parent is writable so the installer can create it.","Fix permissions on the target or parent: chmod +w <parent> / chown.","Use an absolute path or a ~/subpath form this installer supports; avoid ~user syntax.","Run the installer with adequate privileges for the chosen install location."],"exampleFix":"# before\n#   --directory /opt/readonly/bmad      # parent not writable\n#   --directory ~/somefile              # exists but is a file\n#\n# after\n#   --directory ~/projects/my-bmad      # parent (~) is writable\n#   sudo chmod +w /opt/readonly && --directory /opt/readonly/bmad","handlingStrategy":"validation","validationCode":"const dir = ui.expandUserPath(options.directory);\nconst err = ui.validateDirectorySync(dir);\nif (err) {\n  console.error(`Directory '${dir}' is invalid: ${err}. Choose a writable path.`);\n  process.exit(1);\n}","typeGuard":"function isStringPath(p) { return typeof p === 'string' && p.length > 0; }","tryCatchPattern":"try {\n  await ui.run(options);\n} catch (e) {\n  if (/^Invalid directory:/.test(e.message)) {\n    // re-prompt for a writable directory, or fix permissions and retry\n  } else { throw e; }\n}","preventionTips":["Pre-validate --directory with validateDirectorySync before launching the full flow.","Prefer a writable home-relative path; avoid system directories without elevated privileges.","Don't use ~user syntax — expand to an absolute path first."],"tags":["installer","directory-validation","filesystem","permissions"],"backgroundTag":null,"analyzedSha":"b70486b9bdcb0a404d329e2a763b57964e7f1360","analyzedAt":"2026-08-13T01:21:12.247Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}