{"id":"5d714f0524122363","repo":"tj/commander.js","slug":"command-passed-to-addcommand-must-have-a-name","errorCode":null,"errorMessage":"Command passed to .addCommand() must have a name\n- specify the name in Command constructor or using .name()","messagePattern":"Command passed to \\.addCommand\\(\\) must have a name\n- specify the name in Command constructor or using \\.name\\(\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/command.js","lineNumber":291,"sourceCode":"   */\n  showSuggestionAfterError(displaySuggestion = true) {\n    this._showSuggestionAfterError = !!displaySuggestion;\n    return this;\n  }\n\n  /**\n   * Add a prepared subcommand.\n   *\n   * See .command() for creating an attached subcommand which inherits settings from its parent.\n   *\n   * @param {Command} cmd - new subcommand\n   * @param {object} [opts] - configuration options\n   * @return {Command} `this` command for chaining\n   */\n\n  addCommand(cmd, opts) {\n    if (!cmd._name) {\n      throw new Error(`Command passed to .addCommand() must have a name\n- specify the name in Command constructor or using .name()`);\n    }\n\n    opts = opts || {};\n    if (opts.isDefault) this._defaultCommandName = cmd._name;\n    if (opts.noHelp || opts.hidden) cmd._hidden = true; // modifying passed command due to existing implementation\n\n    this._registerCommand(cmd);\n    cmd.parent = this;\n    cmd._checkForBrokenPassThrough();\n\n    return this;\n  }\n\n  /**\n   * Factory routine to create a new unattached argument.\n   *\n   * See .argument() for creating an attached argument, which uses this routine to","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/tj/commander.js/blob/ba6d13ddb4243e5913367734f8c159089ffe7834/lib/command.js#L273-L309","documentation":"Thrown by Command.addCommand() at lib/command.js:290-293 when the subcommand passed in has an empty `_name`. Commander requires every registered subcommand to be addressable by name (for dispatch, help, conflict detection in _registerCommand), so a nameless Command is rejected up front.","triggerScenarios":"`new Command()` with no argument, or `new Command('')`, then `program.addCommand(cmd)`. Also happens when constructing with `.command()` style but forgetting the name, or when the name was meant to be set later via `.name()` but never was.","commonSituations":"Refactor where a Command was created in a factory function and the name parameter was dropped; copy-paste from `.command('name')` examples into the `new Command()` form; dynamic command construction where the name comes from a config that returned undefined.","solutions":["Pass the name in the constructor: `new Command('deploy')`.","Or set it before addCommand: `cmd.name('deploy'); program.addCommand(cmd);`.","If the name is derived dynamically, assert it is a non-empty string before constructing: `if (!name) throw ...`."],"exampleFix":"// before\nconst sub = new Command(); // no name\nprogram.addCommand(sub);\n\n// after\nconst sub = new Command('deploy');\nprogram.addCommand(sub);","handlingStrategy":"validation","validationCode":"function addNamed(program, cmd) {\n  if (!cmd.name?.() && !cmd._name) {\n    throw new Error('Cannot add a nameless subcommand');\n  }\n  if (!cmd.name()) cmd.name(cmd._name || generatedName);\n  return program.addCommand(cmd);\n}","typeGuard":"import { Command } from 'commander';\nfunction isNamedCommand(v: unknown): v is Command {\n  return v instanceof Command && typeof v.name() === 'string' && v.name().length > 0;\n}","tryCatchPattern":null,"preventionTips":["Always pass the name to new Command('name') at construction.","In factories/dynamic loaders, assert cmd.name() is non-empty before addCommand.","Add a unit test that every registered subcommand has a name."],"tags":["commander","subcommand","addcommand","configuration"],"analyzedSha":"ba6d13ddb4243e5913367734f8c159089ffe7834","analyzedAt":"2026-08-03T20:26:04.326Z","schemaVersion":2}