Skip to content
This repository has been archived by the owner on Aug 16, 2021. It is now read-only.

Helper for displaying all causes in the entire error chain #76

Open
emk opened this issue Nov 23, 2017 · 3 comments
Open

Helper for displaying all causes in the entire error chain #76

emk opened this issue Nov 23, 2017 · 3 comments

Comments

@emk
Copy link

emk commented Nov 23, 2017

Thank you for digging into this tricky design problem!

I miss the "chained" error display provided by quick_main! in error-chain. A lot of my software has been designed around showing the various nested error messages. For example:

error reading "avatar_01_01.es.srt2": No such file or directory (os error 2)

Showing the full context of the error provides helpful clues to the user. But failure provides no easy way to get that string, and it seems to encourage the use of errors like:

error reading "avatar_01_01.es.srt2"

This is less ergonomic for users.

One workaround is to write something like this:

    // Decide which command to run, and run it, and print any errors.
    if let Err(err) = run(&args) {
        let mut opt_cause = Some(err.cause());
        let mut first = true;
        while let Some(cause) = opt_cause {
            if first {
                first = false;
            } else {
                write!(io::stderr(), ": ")
                    .expect("unable to write error to stderr");
            }
            write!(io::stderr(), "{}", cause)
                .expect("unable to write error to stderr");
            opt_cause = cause.cause();
        }
        write!(io::stderr(), "\n").expect("unable to write error to stderr");
        process::exit(1);
    }

This is potentially related to #41.

I don't think it's necessary to go as far as quick_main!. It might be enough to have a display_with_causes method or even a DisplayWithCauses newtype, allowing us to write something like:

write!(io::stderr(), "{}\n", err.display_with_causes())

Obviously some of this could be provided by an external crate. But there might be some nice ergonomic improvements to be made here.

emk referenced this issue in emk/subtitles-rs Nov 23, 2017
This would probably look nicer if we had something along the lines of:

https://github.com/withoutboats/failure/issues/62
https://github.com/withoutboats/failure/issues/76

...but it's a good start.
@withoutboats
Copy link
Contributor

I've just merged #54, which implements a causes iterator. I think something like this would be adequate for your use case for now:

let mut stderr = io::stderr();
for fail in err.causes() {
    let _ = writeln!(stderr, "{}", fail);
}

@epage
Copy link

epage commented Nov 28, 2017

For reference, with #54 here is an approximation (meaning I haven't built it) of error-chain:

// Decide which command to run, and run it, and print any errors.
if let Err(err) = run(&args) {
    let mut stderr = io::stderr();
    let mut causes = err.causes();
    writeln!(stderr, "Error: {}", causes.next().expect("`causes` to at least contain `err`"))
        .expect("unable to write error to stderr");
    for cause in causes {
        writeln!(stderr, "Caused by: {}", cause)
            .expect("unable to write error to stderr");
    }
    // The following assumes an `Error`, use `if let Some(backtrace) ...` for a `Fail`
    writeln!(stderr, "{:?}", backtrace)
        .expect("unable to write error to stderr");
    process::exit(1);
}

@lilianmoraru
Copy link

lilianmoraru commented Dec 7, 2017

The error-chain is my favorite feature in error-chain.
I remember rustup failing to download a file from behind the company's proxy and instead of getting the usual misleading error: No such file or directory, I got a very clear chain of errors explaining that:

  1. It failed to access the link
  2. Because it failed to access the link, it failed to download the file
  3. Because it failed to download the file, it does not exist

It made it extremely easy for me to fix the root cause.

Edit(the rustup output when I remove the SOCKS4 proxy):

error: could not download file from 'https://static.rust-lang.org/rustup/release-stable.toml' to '/tmp/rustup-update.T7Ry8gjuIytx/release-stable.toml'
info: caused by: error during download
info: caused by: [7] Couldn't connect to server (Failed to receive SOCKS4 connect request ack.)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants