#error #main #print #debug #display

main_error

Print errors with Display instead of Debug when using ? in main()

3 releases

0.1.2 Sep 12, 2021
0.1.1 Jul 18, 2020
0.1.0 Sep 24, 2019

#370 in Command-line interface

Download history 431/week @ 2023-02-06 416/week @ 2023-02-13 435/week @ 2023-02-20 462/week @ 2023-02-27 612/week @ 2023-03-06 408/week @ 2023-03-13 447/week @ 2023-03-20 333/week @ 2023-03-27 326/week @ 2023-04-03 328/week @ 2023-04-10 313/week @ 2023-04-17 303/week @ 2023-04-24 517/week @ 2023-05-01 264/week @ 2023-05-08 259/week @ 2023-05-15 361/week @ 2023-05-22

1,550 downloads per month
Used in fewer than 12 crates

MIT license

8KB

main_error

Print errors with Display instead of Debug when using ? in main(). For example:

use main_error::MainError;

fn main() -> Result<(), MainError> {
    // This prints
    //   "Error: invalid digit found in string"
    // instead of (if you used `Result<(), Box<dyn Error>>` or similar)
    //   "ParseIntError { kind: InvalidDigit }".
    let number: i32 = "not a number".parse()?;

    Ok(())
}

For more info, see:


lib.rs:

Print errors with [Display] instead of [Debug] when using ? in main().

Use by returning [MainError] as the error type from main(). Example:

use main_error::MainError;

fn main() -> Result<(), MainError> {
    // This prints
    //   "Error: invalid digit found in string"
    // instead of (if you used `Result<(), Box<dyn Error>>` or similar)
    //   "ParseIntError { kind: InvalidDigit }".
    let number: i32 = "not a number".parse()?;

    Ok(())
}

For convenience, you can also use the [MainResult] type. See below for more details.

The Issue

Since Rust 1.26, main() function can return a Result<T, E>. This enables the use of ? for convenient error handling in small programs and quick examples (RFC).

Unfortunately, the error is printed via [Debug] (hardcoded in the standard library, search for "Error:"), which gives not very pretty or human-friendly output.

For example, this program:

# use std::num::ParseIntError;
fn main() -> Result<(), ParseIntError> {
    let num: i32 = "not a number".parse()?;
    // ...
#     Ok(())
}

will print

Error: ParseIntError { kind: InvalidDigit }

Solution

This crate provides [MainError] as a drop-in replacement for the error type E in your main's Result<T, E>. It prints the error via [Display] instead of [Debug], which yields a nicer error message. For example, the program above can be changed to

use main_error::MainError;

fn main() -> Result<(), MainError> {
    let _: i32 = "not a number".parse()?;
    // ...
#    Ok(())
}

and now prints:

Error: invalid digit found in string

Details and Drawbacks

  • [MainError] stores the original error as Box<dyn Error>. This incurs one allocation (on conversion) and one virtual call (on printing). Since there can be exactly one error like this before the program ends, this cost is insignificant.
  • [MainError] implements [From] for all types that can be converted into a Box<dyn Error>.
    1. This allows it to be used in place of any type that implements the [Error] trait (see example above).
    2. It can also be used in place of any type that can be converted to a Box<dyn Error>, e.g., String.
  • [MainError] does not implement the [Error] trait itself. Reasons:
    1. It's not necessary, because the standard library only requires E: Debug for main() -> Result<T, E>.
    2. You should only be using MainError for main() anyway, whereas the Error trait is more for interoparability between libraries.
    3. One simply cannot implement Error for MainError, because this would create an overlapping impl.
      Explanation:
  • [MainError] implements [Debug] in terms of [Display] of the underlying error. This is hacky, but unfortunately [Debug] as the output for the main error case is stable now. The "Error: " part at the beginning of the output comes from the standard library, thus it cannot be changed.

No runtime deps