You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Duplicate subcommands are silently ignored by ArgumentParser #976
Replace this paragraph with an explanation of how to reproduce the incorrect behavior. This could include a code listing for a reduced version of your command, or a link to the code that is exhibiting the issue.
Have a command with two subcommands which have the same commandName in their CommandConfiguration.
Expected behavior
Describe what you expect to happen.
I would expect ArgumentParser to either print a warning or better yet throw an error (possibly even a fatalError) or call ParsableArguments.exit(withError:), whenever the application starts.
Actual behavior
Describe or copy/paste the behavior you observe.
Basically when there are two or more subcommands which have the same commandName only the first command can be invoked. The second one still exists and is listed in --help, but cannot be invoked, because calling the command only calls the first command.
As a small work around it's possible to do something like this, though i think it makes more sense if Argument-Parser would do something like this on it's own:
/// A `ParsableCommand` which can validate *all* descendants. Therefore it on the root command.
/// If there are duplicate commands the command will early exit before doing anything.
///
/// IMPORTANT: if you overwrite `validate` you should call `validateCommandSubtree(command: Self.self)`,
/// otherwise this protocol is useless
publicprotocolValidatedRootCommand:ParsableCommand{}publicextensionValidatedRootCommand{func validate()throws{validateCommandSubtree(command:Self.self)}func validateCommandSubtree(command:anyParsableCommand.Type, commandPath:[String?]=[]){letcommandPath= commandPath +[command.configuration.commandName]letfailingCommands:[String?:[anyParsableCommand.Type]]= command.configuration.subcommands
.grouped{ $0.configuration.commandName }.filter{ $0.value.count >1}guard failingCommands.isEmpty else{leterrorTable= failingCommands.map{return"- '\($0.key, default:"<nil>")':\n - \(String($0.value.map{String(describing: $0)}.joined(separator:", ")))"}.joined(separator:"\n\n")
// NOTE: throwing is not enough, we need to exit
Self.exit(withError:ValidationError("At command '\(String(commandPath.compacted().joined(separator:"")))' there are multiple possible subcommand-types:\n\(errorTable)"))}forsubcommandin command.configuration.subcommands {validateCommandSubtree(command: subcommand, commandPath: commandPath)}}}
Activity
true-false-maybe commentedon Sep 24, 2026
As a small work around it's possible to do something like this, though i think it makes more sense if Argument-Parser would do something like this on it's own: