tj/commander.js · error · Error
only the last argument can be variadic '${previousArgument.n
Error message
only the last argument can be variadic '${previousArgument.name()}' What it means
Thrown by Command.addArgument() at lib/command.js:378-382 when an argument is added after an argument that is already variadic (name ending in `...`). Variadic arguments capture all remaining positional tokens, so nothing may follow them; Commander enforces this at registration time.
Source
Thrown at lib/command.js:379
names
.trim()
.split(/ +/)
.forEach((detail) => {
this.argument(detail);
});
return this;
}
/**
* Define argument syntax for command, adding a prepared argument.
*
* @param {Argument} argument
* @return {Command} `this` command for chaining
*/
addArgument(argument) {
const previousArgument = this.registeredArguments.slice(-1)[0];
if (previousArgument?.variadic) {
throw new Error(
`only the last argument can be variadic '${previousArgument.name()}'`,
);
}
if (
argument.required &&
argument.defaultValue !== undefined &&
argument.parseArg === undefined
) {
throw new Error(
`a default value for a required argument is never used: '${argument.name()}'`,
);
}
this.registeredArguments.push(argument);
return this;
}
/**
* Customise or override default help command. By default a help command is automatically added if your command has subcommands.View on GitHub (pinned to ba6d13ddb4)
Solutions
- Move the variadic to the end: `.arguments('<dest> <files...>')` is wrong order semantically — instead restructure to `.argument('<output>').argument('<inputs...>')` so variadic is last.
- If you need 'sources... then dest', require dest as an option (`.option('-o, --out <path>')`) instead of a positional, then keep `<files...>` as the sole variadic positional.
- Split into two commands or use a delimiter the user passes.
Example fix
// before (throws: variadic not last)
.arguments('<files...> <dest>')
// after (variadic last, dest as option)
.argument('<files...>')
.option('-o, --out <dest>', 'destination') Defensive patterns
Strategy: validation
Validate before calling
// Ensure variadic is last when building args dynamically
function addArgsSafe(cmd, specs) {
const lastVariadicIdx = specs.findIndex(s => s.endsWith('...'));
if (lastVariadicIdx !== -1 && lastVariadicIdx !== specs.length - 1) {
throw new Error('variadic argument must be the last one');
}
specs.forEach(s => cmd.argument(s));
} Prevention
- Place variadic arguments last by convention; review .arguments() strings carefully.
- Prefer options for trailing required tokens (e.g. -o/--out) when the variadic must come first semantically.
- Lint .arguments() calls in review.
When it happens
Trigger: `.arguments('<files...> <dest>')`, or chained `.argument('<inputs...>').argument('<output>')`. The check looks at the last registered argument: if it is variadic, adding another throws.
Common situations: Trying to express 'many source files then a destination' with the variadic in the wrong slot; converting a fixed-arity signature to variadic and forgetting to reorder; misreading docs that show variadic must be last.
Related errors
- a default value for a required argument is never used: '${ar
- Command passed to .addCommand() must have a name - specify t
- Unexpected value for event passed to hook : '${event}'. Expe
- Cannot add option '${option.flags}'${this._name && ` to comm
- cannot add command '${newCmd}' as already have command '${ex
AI-assisted analysis of tj/commander.js@ba6d13ddb4 (2026-08-03).
Data as JSON: /data/errors/a56ba73932080ff1.json.
Report an issue: GitHub.