Skip to content

Reporting errors

Adam Bajguz edited this page Aug 22, 2020 · 3 revisions

You may have noticed that commands in Typin don't return exit codes. This is by design as exit codes are considered a higher-level infrastructural concern and thus handled by CliApplication, not by individual commands.

Commands can instead report execution failure by throwing CommandException or any other exception. When an exception is thrown, CliApplication will catch it, print the error, and return 1 as the exit code to the calling process.

If you want to communicate a specific error through exit code, you can instead throw an instance of CommandException which takes an exit code as a parameter. When a command throws an exception of type CommandException, it is assumed that this was a result of a handled error and, as such, only the exception message will be printed to the error stream. If a command throws an exception of any other type, the full stack trace will be printed as well.

Note: Unix systems rely on 8-bit unsigned integers for exit codes, so it's strongly recommended to use values between 1 and 255 to avoid potential overflow issues.

[Command]
public class DivideCommand : ICommand
{
    [CommandOption("dividend", IsRequired = true)]
    public double Dividend { get; set; }

    [CommandOption("divisor", IsRequired = true)]
    public double Divisor { get; set; }

    public ValueTask ExecuteAsync(IConsole console)
    {
        if (Math.Abs(Divisor) < double.Epsilon)
        {
            // This will print the error and set exit code to 133
            throw new CommandException("Division by zero is not supported.", 133);
        }

        var result = Dividend / Divisor;
        console.Output.WriteLine(result);

        return default;
    }
}
> myapp.exe --dividend 10 --divisor 0

Division by zero is not supported.


> $LastExitCode

133

You can also specify the showHelp parameter to instruct whether to show the help text for the current command after printing the error:

[Command]
public class ExampleCommand : ICommand
{
    public ValueTask ExecuteAsync(IConsole console)
    {
        throw new CommandException("Something went wrong.", showHelp: true);
    }
}
Clone this wiki locally