tj/commander.js · error · Error

Can not call parse again when storeOptionsAsProperties is tr

Error message

Can not call parse again when storeOptionsAsProperties is true.
- either make a new Command for each call to parse, or stop storing options as properties

What it means

Thrown by Command.restoreStateBeforeParse() at lib/command.js:1171-1174 when parse() is called a second time on the same Command while storeOptionsAsProperties is true. With property-storage, option values live directly on `this` and cannot be cleanly reset across parses (the saved state only deep-restores _optionValues/_optionValueSources). Commander forbids the combo rather than risk stale or merged state.

Source

Thrown at lib/command.js:1173

    this._savedState = {
      // name is stable if supplied by author, but may be unspecified for root command and deduced during parsing
      _name: this._name,
      // option values before parse have default values (including false for negated options)
      // shallow clones
      _optionValues: { ...this._optionValues },
      _optionValueSources: { ...this._optionValueSources },
    };
  }

  /**
   * Restore state before parse for calls after the first.
   * Not usually called directly, but available for subclasses to save their custom state.
   *
   * This is called in a lazy way. Only commands used in parsing chain will have state restored.
   */
  restoreStateBeforeParse() {
    if (this._storeOptionsAsProperties)
      throw new Error(`Can not call parse again when storeOptionsAsProperties is true.
- either make a new Command for each call to parse, or stop storing options as properties`);

    // clear state from _prepareUserArgs
    this._name = this._savedState._name;
    this._scriptPath = null;
    this.rawArgs = [];
    // clear state from setOptionValueWithSource
    this._optionValues = { ...this._savedState._optionValues };
    this._optionValueSources = { ...this._savedState._optionValueSources };
    // clear state from _parseCommand
    this.args = [];
    // clear state from _processArguments
    this.processedArgs = [];
  }

  /**
   * Throw if expected executable is missing. Add lots of help for author.
   *

View on GitHub (pinned to ba6d13ddb4)

Solutions

  1. Stop storing options as properties: `program.storeOptionsAsProperties(false)` (or just omit the call) and access via `.opts()`. Then re-parse is allowed.
  2. Or construct a fresh Command for each parse call.
  3. In tests, use beforeEach to rebuild the program rather than reusing.

Example fix

// before (throws on second parse)
program.storeOptionsAsProperties();
program.parse();
program.parse();

// after (re-parse allowed, use .opts())
program.parse();
program.parse();
const opts = program.opts();
Defensive patterns

Strategy: fallback

Validate before calling

// Detect the risky combo before second parse
function assertCanReparse(cmd) {
  if (cmd._storeOptionsAsProperties) {
    throw new Error('Cannot re-parse with storeOptionsAsProperties=true; rebuild the Command or use .opts()');
  }
}

Prevention

When it happens

Trigger: `program.storeOptionsAsProperties(); program.parse(); /* later */ program.parse();` — second parse hits the guard. Common in tests that parse twice, or long-lived REPL/server embedding Commander.

Common situations: Test suites reusing the program instance; interactive tools that re-parse user input; migration from Commander v4 where property storage + re-parse happened to work.

Related errors


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