anyhow
anyhow copied to clipboard
[Question] In `{:#?}` why is the outermost context called "caused by" and how is `Context` expected to be used?
Suppose I have code like this (see this playground):
use anyhow::Context;
fn my_thing(path: &Path, extra_sauce: bool) -> anyhow::Result<()> {
std_or_some_external_lib::do_other_thing()
.context(format!("path: {:?}", path.display()))
.context(format!("extra_sauce: {:?}", extra_sauce))?;
Ok(())
}
Let's suppose do_other_thing
results in an error which displays as failed to do other thing because <reason>
…
Now what I intend by the code above is "if do_other_thing
results in an error, then when describing that error cause to a user, provide this extra context for the user to have more context about the cause", so I would expect to see this kind of output:
Error: failed to do other thing because <reason>
Context:
0: path: "/tmp/non-existent"
1: extra_sauce: true
But for some reason the {:#?}
display calls the outermost "the cause" so it shows this output:
Error: extra_sauce: true
Caused by:
0: path: "/tmp/non-existent"
1: failed to do other thing because <reason>
This output seems backwards and confusing to me. Am I somehow misunderstanding Context
? How should it be used?
It feels like it needs to be used like this in order to have clearer error messages, which seems clunky and redundant:
use anyhow::Context;
fn my_thing(path: &Path, extra_sauce: bool) -> anyhow::Result<()> {
std_or_some_external_lib::do_other_thing()
.context(format!("path: {:?}", path.display()))
.context(format!("extra_sauce: {:?}", extra_sauce))
.context("failed to do some other thing".to_string())?; // Why am I describing the error of `do_other_thing` which already describes itself?
Ok(())
}
Based on my rereading of Context#example it seems like I need to retrain myself to rename Context::context
as Context::caused_by
…
In other words, arguments to that method should always describe a cause of an error, but not "auxillary context the user should know about the cause". Is that how to think of it?