Printing errors in Rust

In Rust an Error could have a cause which could also have a cause … Put another way: there is an error chain.

Sometimes it might be useful to print the whole error chain; probably not when showing errors to users/clients, but most probably when logging in order to understand the root cause of an error.

In Rust we also have two very prominent “error libraries”: anyhow and thiserror. Simplified, the former is for binaries and the latter for libraries.

anyhow has two very nice features. First, we can attach “context” to almost any error via the context extension method, which essentially creates an anyhow::Error with the error at hand as source. Second, we can use the alternate way of formatting – "{:#}" – to print the whole error chain:

error!(error = format!("{error:#}"), "cannot do this");

This snippet is assuming the tracing library being used and some error of type anyhow::Error in scope.

All right, this works fine for binaries, i.e. when we can use anyhow::Error. But what if we want to print – using tracing::error or similar – errors in library code? There we typically do not use anyhow::Error, but instead some custom error types, probably derived by thiserror. Using the above snippet for such a custom error would just print the error and omit the sources.

To get the whole error chain printed, we could either write some custom print_error_chain function and invoke it every time we want to print an error in library code, or simply leverage anyhow. Not the full anyhow machinery, but just the anyhow! macro, which is able to transform any error into an anyhow::Error:

error!(error = format!("{:#}", anyhow!(error)), "cannot do this");

This way we do not use anyhow::Error or anyhow::Result in any signatures (parameters or return types) in our library code, but we get the error chains printed very easily.

What do you think about this approach? I am looking forward to your comments.