Search code examples
rusterror-handling

anyhow: Return nested/wrapped errors


use anyhow::Context;

fancy_module::run()
.await
.with_context(|| {
    format!("An error has been found")
})?;

From what I understand, when run returns an error, we return "An error has been found". But this message is not really meaningful. I would like to also return the error that run returns. Something like format!("An error has been found {}", e). How do I get e returned by run?

I could do that in multiple lines of code. By fetching the result of run and then having a match statement. Is there a nicer way of doing that?


Solution

  • From what I understand, when run returns an error, we return "An error has been found".

    Not correct! context and with_context create a wrapper around the underlying error value to introduce additional context, but the original error is kept within!

    Once you try displaying the error, you will see something of this sort:

    Error: An error has been found
    
    Caused by:
        No such file or directory (os error 2)
    

    (This also shows that "An error has been found" is a poor choice of words for creating additional context.)

    I would like to also return the error that run returns. Something like format!("An error has been found {}", e).

    That used to be a reasonable design decision in the past, but the current guidelines for error type design are against including the source error in the display message, unless that source error is also not reachable in the source error chain. The context methods will put the error in the source chain, so including that error's message into the top level error's message is ill advised.

    How do I get e returned by run?

    See the chain method in order to traverse the chain of source errors and so enable you to peek into underlying causes. Still, anyhow's error type was mostly designed to be opaque. If you need better introspection into what the error entails or easier pattern matching on errors, consider using a structural error type instead of anyhow::Error (snafu or thiserror can help you build them).

    See also: