dotnet / dotnet/command-line-api

Command Validators are still run when a parser fails

Open
#2,645 9 comments 0 reactions 1 assignee Claimed by @adamsitnik View on GitHub
Area-Documentation
Dominant language
C#
Stars
3.7k
Forks
428
PR merge metrics
No merged PRs in 30d

Description

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:

```cs
using System.CommandLine;

Option intOption = new("--int")
{
Validators =
{
result =>
{
int value = result.GetValueOrDefault();
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.<$>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.$(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:

```cs
using System.CommandLine;

Option 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();
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.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.