RicoSuter/NSwag · error · InvalidOperationException
The command '" + name + "' has already been added.
Error message
The command '" + name + "' has already been added.
What it means
RegisterCommand(name, type) keeps a dictionary of command names; adding a name that already exists throws InvalidOperationException. It's a duplicate-registration guard, typically hit when the same command is registered twice.
Solutions
- Guard with processor.ContainsCommand(name) (or check the registry) before calling RegisterCommand.
- Fix initialization so command registration runs only once.
- Rename one of the conflicting CommandAttribute names.
- If overwriting is intended, use the registry's replace/remove API or a try/catch around duplicate registration.
Example fix
// before
processor.RegisterCommand("openapi2csclient", typeof(OpenApiToCSharpClientCommand));
processor.RegisterCommand("openapi2csclient", typeof(MyClientCommand)); // throws
// after
if (!processor.ContainsCommand("openapi2csclient"))
processor.RegisterCommand("openapi2csclient", typeof(MyClientCommand)); Defensive patterns
Strategy: validation
Validate before calling
if (processor.ContainsCommand(name))
Console.Error.WriteLine($"Command '{name}' already registered; skipping.");
else
processor.RegisterCommand(name, commandType); Try / catch
try { processor.RegisterCommand(name, commandType); }
catch (InvalidOperationException ex) when (ex.Message.Contains("has already been added")) { /* idempotent registration: ignore */ } Prevention
- Register commands once during a single bootstrap phase
- Guard duplicate registrations with ContainsCommand
- Ensure each command's CommandAttribute name is unique across the assembly
When it happens
Trigger: Calling processor.RegisterCommand("openapi", ...), or RegisterCommand(typeof(X)) for a type whose CommandAttribute name is already registered — including case/registry-level duplicates where the exact same key string is added twice during processor setup.
Common situations: Registering commands in code that runs twice (double initialization, re-executed bootstrap); two command classes sharing the same CommandAttribute name; plugin loading that re-registers built-in NSwag commands.
Related errors
- The command class is missing the CommandAttribute attribute.
- The specified runtime in the document
- Project outputs could not be located in
- The ouput of is a 32-bit application and requires…
- The ouput of is a 64-bit application and requires…
AI-assisted analysis of RicoSuter/NSwag@63daf8fcc3 (2026-09-14).
Data as JSON: /api/errors/5bfb7c3a583963cf.
Report an issue: GitHub.
Appendix: source
Thrown at src/NSwag.Commands/NConsole/CommandLineProcessor.cs:89
/// <exception cref="InvalidOperationException">The command has already been added.</exception>
/// <exception cref="InvalidOperationException">The command class is missing the CommandAttribute attribute.</exception>
public void RegisterCommand(Type commandType)
{
var commandAttribute = commandType.GetTypeInfo().GetCustomAttribute<CommandAttribute>();
if (commandAttribute == null)
throw new InvalidOperationException("The command class is missing the CommandAttribute attribute.");
RegisterCommand(commandAttribute.Name, commandType);
}
/// <summary>Adds a command.</summary>
/// <param name="name">The name of the command.</param>
/// <param name="commandType">Type of the command.</param>
/// <exception cref="InvalidOperationException">The command has already been added.</exception>
public void RegisterCommand(string name, Type commandType)
{
if (_commands.ContainsKey(name))
throw new InvalidOperationException("The command '" + name + "' has already been added.");
_commands.Add(name.ToLowerInvariant(), commandType);
}
/// <summary>Processes the command in the given command line arguments.</summary>
/// <param name="args">The arguments.</param>
/// <param name="input">The input for the first command.</param>
/// <returns>The executed command.</returns>
/// <exception cref="InvalidOperationException">The command could not be found.</exception>
/// <exception cref="InvalidOperationException">No dependency resolver available to create a command without default constructor.</exception>
public async Task<IList<CommandResult>> ProcessAsync(string[] args, object input = null)
{
var results = new List<CommandResult>();
var commands = new List<string[]>();
var commandArgs = new List<string>();
foreach (var arg in args)
{View on GitHub (pinned to 63daf8fcc3)