tj/commander.js · error · InvalidArgumentError

Allowed choices are ${this.argChoices.join(', ')}.

Error message

Allowed choices are ${this.argChoices.join(', ')}.

What it means

Thrown by Argument.choices() (lib/argument.js:100-105) when an argument value is not in the configured allow-list. The choices() method installs a parseArg that calls Array.includes on this.argChoices; a miss throws InvalidArgumentError listing the allowed values. This is the argument-side analogue of option choices.

Source

Thrown at lib/argument.js:102

   */

  argParser(fn) {
    this.parseArg = fn;
    return this;
  }

  /**
   * Only allow argument value to be one of choices.
   *
   * @param {string[]} values
   * @return {Argument}
   */

  choices(values) {
    this.argChoices = values.slice();
    this.parseArg = (arg, previous) => {
      if (!this.argChoices.includes(arg)) {
        throw new InvalidArgumentError(
          `Allowed choices are ${this.argChoices.join(', ')}.`,
        );
      }
      if (this.variadic) {
        return this._collectValue(arg, previous);
      }
      return arg;
    };
    return this;
  }

  /**
   * Make argument required.
   *
   * @returns {Argument}
   */
  argRequired() {
    this.required = true;

View on GitHub (pinned to ba6d13ddb4)

Solutions

  1. Pass one of the listed allowed values.
  2. If the value should be valid, add it to the choices() array.
  3. Normalize input case before choices() — e.g. `.choices(['a','b'])` plus a parser that lowercases — or call choices with the full set including upper-case variants.
  4. Surface the allowed set in --help by describing it in the argument description string.

Example fix

// before
.argument('<mode>', 'mode').choices(['read', 'write'])
// prog READ -> throws

// after
.argument('<mode>', 'mode', (v) => v.toLowerCase()).choices(['read', 'write'])
Defensive patterns

Strategy: validation

Validate before calling

const ALLOWED = ['read', 'write', 'append'];
const value = process.argv[idx];
if (!ALLOWED.includes(value)) {
  console.error(`mode must be one of: ${ALLOWED.join(', ')}`);
  process.exit(2);
}

Type guard

const MODES = ['read', 'write', 'append'] as const;
type Mode = typeof MODES[number];
function isMode(v: unknown): v is Mode {
  return typeof v === 'string' && (MODES as readonly string[]).includes(v);
}

Try / catch

try { await program.parseAsync(); }
catch (e) {
  if (e.code === 'commander.invalidArgument' && /Allowed choices/.test(e.message)) {
    console.error(e.message); process.exit(2);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `.argument('<mode>', 'mode', null).choices(['a','b','c'])` then running the program with a value outside ['a','b','c'], e.g. `prog d`. Each variadic value is checked individually, so `prog a x b` also fails on 'x'.

Common situations: Typos in the supplied value; case mismatch ('A' vs 'a' — choices is case-sensitive); a new valid choice added to the backend but not to the choices() list; upstream script forwarding an unfiltered env value.

Related errors


AI-assisted analysis of tj/commander.js@ba6d13ddb4 (2026-08-03). Data as JSON: /data/errors/378cc8ef232b453c.json. Report an issue: GitHub.