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

  1. Guard with processor.ContainsCommand(name) (or check the registry) before calling RegisterCommand.
  2. Fix initialization so command registration runs only once.
  3. Rename one of the conflicting CommandAttribute names.
  4. 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

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


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)