How to exit on error

Say I have something like this:

fn main() {
    let input = match user_input::args() {
        Ok(input) => input,
        Err(e) => {
            eprintln!("{}", e);
            // return or process::exit(1) ?
        }
    };
}

If I don't want the program to continue in the error case, should I just return or should I do process::exit(1), or does it matter? In this case I'm building a simple command line tool.

If you only return your program will terminate with the return code 0 which normally indicates a successful execution. If you want to indicate that your program did not run successfully you should use process::exit(1).

3 Likes

A common pattern I use for command line programs is to structure it in the following way

fn _main() -> anyhow::Result<()> {
    // Primary application code goes here
    let args = parse_args()?; // this is just an example of a function you could have
    // …
    Ok(())
}

fn main() {
    if let Err(e) = _main() {
        eprintln!(“Error: {:#?}”, e);
        std::process::exit(1)
    }
}

anyhow is a popular crate for error handling which makes it easy to not worry about error types in this case. But generally this lets you use ? to early return from the new _main function while also giving a nicer error message and having the application return a non zero value on error.

6 Likes

A good pattern but I'd rather name _main() try_main(). This aligns more with Rust's naming conventions as an _ as prefix indicates unused stuff to the compiler.

Also I want to mention the structopt crate for parsing command line arguments. It just saves a lot of time and pain.

1 Like

The shortest way is:

fn main() {
    let input = user_input::args().unwrap(); // panics on error

    // input is available from here...
}

Why have the split at all?

fn main() can return a Result<_, _>, so why not use that directly?

Because I like to print a nicer formatted error message which I didn’t think was customizable putting the Result directly on main.

1 Like

Currently returning a Result from main causes the Debug representation of the error to be printed on Err. @drewkett's example uses the alternative "pretty" Debug representation, and when I write this pattern I tend to use the Display representation (for an error type that implements std::error::Error).

There's been some discussion in the error handling project group about using specialization to print the Display representation in main-returning-Result when the error type implements Error, here's a thread:

https://github.com/rust-lang/project-error-handling/issues/39

2 Likes

Interesting. I actually prefer the Debug impl (alternate flag or no, generally that's only a matter of formatting) because it gives me more actionable information on what to do about it without having to translate it back to the error value.

However, if it was a user-facing app, I can see the value in using Display printing instead.

2 Likes

To be perfectly honest, I didn’t realize that a Result on main did some form of pretty printing on error. I have been doing things the way I have since before you could put Result on main so I guess I never checked what that printed.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.