bmad-code-org/BMAD-METHOD · error · Error

Invalid directory: ${validation}

Error message

Invalid directory: ${validation}

What it means

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).

Source

Thrown at tools/installer/ui.js:252

      semver.prerelease(installerPackageJson.version) !== null &&
      !channelOptions.global &&
      channelOptions.nextSet.size === 0 &&
      channelOptions.pins.size === 0
    ) {
      channelOptions.global = 'next';
      await prompts.log.info(
        'Launched from a prerelease — installing all external modules from main HEAD (next channel). Pass --all-stable or --pin to override.',
      );
    }

    // Get directory from options or prompt
    let confirmedDirectory;
    if (options.directory) {
      // Use provided directory from command-line
      const expandedDir = this.expandUserPath(options.directory);
      const validation = this.validateDirectorySync(expandedDir);
      if (validation) {
        throw new Error(`Invalid directory: ${validation}`);
      }
      confirmedDirectory = expandedDir;
      await prompts.log.info(`Using directory from command-line: ${confirmedDirectory}`);
    } else {
      confirmedDirectory = await this.getConfirmedDirectory();
    }

    const { Installer } = require('./core/installer');
    const installer = new Installer();
    const { bmadDir } = await installer.findBmadDir(confirmedDirectory);

    // Check if there's an existing BMAD installation
    const hasExistingInstall = await fs.pathExists(bmadDir);

    // Track action type (only set if there's an existing installation)
    let actionType;

    // Only show action menu if there's an existing installation

View on GitHub (pinned to b70486b9bd)

Solutions

  1. Pass a directory that exists and is writable, or whose nearest existing parent is writable so the installer can create it.
  2. Fix permissions on the target or parent: chmod +w <parent> / chown.
  3. Use an absolute path or a ~/subpath form this installer supports; avoid ~user syntax.
  4. Run the installer with adequate privileges for the chosen install location.

Example fix

# before
#   --directory /opt/readonly/bmad      # parent not writable
#   --directory ~/somefile              # exists but is a file
#
# after
#   --directory ~/projects/my-bmad      # parent (~) is writable
#   sudo chmod +w /opt/readonly && --directory /opt/readonly/bmad
Defensive patterns

Strategy: validation

Validate before calling

const dir = ui.expandUserPath(options.directory);
const err = ui.validateDirectorySync(dir);
if (err) {
  console.error(`Directory '${dir}' is invalid: ${err}. Choose a writable path.`);
  process.exit(1);
}

Type guard

function isStringPath(p) { return typeof p === 'string' && p.length > 0; }

Try / catch

try {
  await ui.run(options);
} catch (e) {
  if (/^Invalid directory:/.test(e.message)) {
    // re-prompt for a writable directory, or fix permissions and retry
  } else { throw e; }
}

Prevention

When it happens

Trigger: 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).

Common situations: Wrong --directory argument; read-only filesystem; pointing at a file; permission denied; using ~otheruser which isn't supported.

Related errors


AI-assisted analysis of bmad-code-org/BMAD-METHOD@b70486b9bd (2026-08-13). Data as JSON: /api/errors/a39667b658d954e0. Report an issue: GitHub.