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

Invalid action: . Valid actions

Error message

Invalid action: ${options.action}. Valid actions: ${validActions.join(', ')}

What it means

Thrown when --action <value> is passed but the value isn't in the dynamically-built choices list. Choices depend on install state: 'update' is always present for an existing install; 'quick-update' only appears when an existing install is detected. The valid set is printed in the message.

Solutions

  1. Use one of the actions printed in the error message (typically 'update' or 'quick-update').
  2. For a fresh install, omit --action — it only gates the existing-install menu.
  3. Ensure an existing BMAD install is present if you want quick-update.

Example fix

# before
#   --action install                       # not a valid action
#   --action quick-update                  # no existing install present
#
# after
#   --action update                        # valid for existing installs
#   (fresh install: drop --action entirely)
Defensive patterns

Strategy: validation

Validate before calling

const VALID = new Set(['update', 'quick-update']);
if (options.action && !VALID.has(options.action)) {
  console.error(`--action must be one of: ${[...VALID].join(', ')}. Omit for fresh installs.`);
  process.exit(1);
}

Type guard

function isValidAction(a, hasExistingInstall) {
  if (a === 'update') return true;
  if (a === 'quick-update') return hasExistingInstall;
  return false;
}

Try / catch

try {
  await ui.run(options);
} catch (e) {
  if (/^Invalid action:/.test(e.message)) {
    // drop --action and let the menu (or --yes) choose
    delete options.action;
    await ui.run(options);
  } else { throw e; }
}

Prevention

When it happens

Trigger: Passing --action install or --action foo; passing --action quick-update against a directory with no existing _bmad install (so quick-update isn't offered).

Common situations: Typo in the action name; using quick-update against a fresh directory; version skew between docs and installer; passing an action that only applies to existing installs.

Related errors


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

Appendix: source

Thrown at tools/installer/ui.js:293

      // Build menu choices dynamically
      const choices = [];

      // Always show Quick Update first (allows refreshing installation even on same version)
      if (existingInstall.installed) {
        choices.push({
          name: 'Quick Update',
          value: 'quick-update',
        });
      }

      // Common actions
      choices.push({ name: 'Modify BMAD Installation', value: 'update' });

      // Check if action is provided via command-line
      if (options.action) {
        const validActions = choices.map((c) => c.value);
        if (!validActions.includes(options.action)) {
          throw new Error(`Invalid action: ${options.action}. Valid actions: ${validActions.join(', ')}`);
        }
        actionType = options.action;
        await prompts.log.info(`Using action from command-line: ${actionType}`);
      } else if (options.yes) {
        // Default to quick-update if available, unless flags that require the
        // full update path are present (e.g. --custom-source which re-clones
        // modules at a new version — quick-update skips that entirely).
        if (choices.length === 0) {
          throw new Error('No valid actions available for this installation');
        }
        const hasQuickUpdate = choices.some((c) => c.value === 'quick-update');
        const needsFullUpdate = !!options.customSource;
        actionType = hasQuickUpdate && !needsFullUpdate ? 'quick-update' : (choices.find((c) => c.value === 'update') || choices[0]).value;
        await prompts.log.info(`Non-interactive mode (--yes): defaulting to ${actionType}`);
      } else {
        actionType = await prompts.select({
          message: 'How would you like to proceed?',
          choices: choices,

View on GitHub (pinned to b70486b9bd)