Skip to content

Command Validators are still run when a parser fails #2645

@Choosechee

Description

@Choosechee

If the default or custom parser for an Option adds an error, its Validators are still run. This is a problem because an exception will be thrown when a validator tries to get the value. Here is an example:

using System.CommandLine;

Option<int> intOption = new("--int")
{
    Validators =
    {
        result =>
        {
            int value = result.GetValueOrDefault<int>();
            if (value < 1)
                result.AddError("Value must be at least 1.");
        }
    }
};

RootCommand command = new()
{
    intOption
};
command.SetAction(result => Console.WriteLine("Command ran successfully"));

command.Parse(["--int", "nonsense"]).Invoke();

Running the code on my system gives this hostile error message:

Unhandled exception. System.InvalidOperationException: Cannot parse argument 'nonsense' for option '--int' as expected type 'System.Int32'.
   at System.CommandLine.Binding.ArgumentConverter.GetValueOrDefault[T](ArgumentConversionResult result)
   at System.CommandLine.Parsing.OptionResult.GetValueOrDefault[T]()
   at Program.<>c.<<Main>$>b__0_1(OptionResult result) in /home/choosechee/RiderProjects/CommandLineIssue/CommandLineIssue/Program.cs:line 9
   at System.CommandLine.Parsing.CommandResult.ValidateOptions(Boolean completeValidation)
   at System.CommandLine.Parsing.CommandResult.Validate(Boolean completeValidation)
   at System.CommandLine.Parsing.ParseOperation.Validate()
   at System.CommandLine.Parsing.ParseOperation.Parse()
   at System.CommandLine.Parsing.CommandLineParser.Parse(Command command, IReadOnlyList`1 arguments, String rawInput, CommandLineConfiguration configuration)
   at System.CommandLine.Parsing.CommandLineParser.Parse(Command command, IReadOnlyList`1 args, CommandLineConfiguration configuration)
   at System.CommandLine.Command.Parse(IReadOnlyList`1 args, CommandLineConfiguration configuration)
   at Program.<Main>$(String[] args) in /home/choosechee/RiderProjects/CommandLineIssue/CommandLineIssue/Program.cs:line 22

Process finished with exit code 134.

If I remove the validator, it gives the expected friendlier error message:

Cannot parse argument 'nonsense' for option '--int' as expected type 'System.Int32'.

Description:

Usage:
  CommandLineIssue [options]

Options:
  -?, -h, --help  Show help and usage information
  --version       Show version information
  --int


Process finished with exit code 0.

It happens with a CustomParser as well:

using System.CommandLine;

Option<int> intOption = new("--int")
{
    CustomParser = result =>
    {
        if (int.TryParse(result.Tokens.Single().Value, out int value))
            return value;
        
        result.AddError("Value must be an integer."); // cause of exception
        return -1;
    },
    Validators =
    {
        result =>
        {
            int value = result.GetValueOrDefault<int>();
            if (value < 1)
                result.AddError("Value must be at least 1.");
        }
    }
};

RootCommand command = new()
{
    intOption
};
command.SetAction(result => Console.WriteLine("Command ran successfully"));

command.Parse(["--int", "nonsense"]).Invoke();
Unhandled exception. System.InvalidOperationException: Value must be an integer.
   at System.CommandLine.Binding.ArgumentConverter.GetValueOrDefault[T](ArgumentConversionResult result)
   at System.CommandLine.Parsing.OptionResult.GetValueOrDefault[T]()
  ...yadda yadda yadda

Process finished with exit code 134.

I can put the validator code that gets the value in a try-catch block to fix this, but I think this is unintuitive to have to do this. I think Validators should not be run when parsing fails, or at least run in a try-catch block to handle these exceptions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions