-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Document the need to handle the underlying error source
explicitly
#59
Comments
I was bit by this behavior recently as well. I had it on my backlog to file an issue about it, but I see Ed already has. Thanks Ed. I'll add my experiences: I've been advocating for migrating more projects over to let temp = tempfile::tempdir().unwrap();
let path = temp.path().join("doesnotexist.txt");
let result = std::fs::read(&path);
let error_string = match result {
Ok(_) => panic!("Expected an error"),
Err(e) => format!("{e}"),
};
let result = fs_err::read(&path);
let fs_error_string = match result {
Ok(_) => panic!("Expected an error"),
Err(e) => format!("{e}"),
};
assert!(
fs_error_string.contains(&error_string),
"Expected FS error '{fs_error_string}' to contain '{error_string}' but it did not"
); with
The main motivation for switching to Moving forwardsAdding docs to spell out the behavior and explicit recommendations could be good. We could also introduce some behavior changes behind feature flags. If we wanted to preserve the existing default the feature could be I'm biased in that this is my main use case (not using anyhow), I also think if you consider the two failure modes it's better to have duplicate information that someone can look up docs for how to disable than it is to have insufficient information and not realize they're missing anything. I am therefore advocating for:
What do you think @andrewhickman? Would you be willing to review a PR for something like that? |
close andrewhickman#59 Changes the default behavior so that the output in the readme now matches the output a user would see when they use the library. Specifically, it now includes the original `std::io::Error` in the output. It introduces a feature `anyhow`. By default: - By default: fs-err will include `std::io::Error` in the Display output, and return `None` from `Error::source()` - With `anyhow` fs-err will not include std::io::Error in the Display output, and return `Some(std::io::Error)` from `Error::source()` This is based on the guidance from andrewhickman#51. That discussion links to this 2020 discussion rust-lang/project-error-handling#23 that suggests that you should either print the source and return `None` from `Error::source()` (https://doc.rust-lang.org/std/error/trait.Error.html#method.source) or not print anything and return `Some(E)`. This allows users of anyhow (or similar) libraries to configure fs-err for the behavior they desire, while not hiding information by default from unsuspecting adopters that are not using those libraries. It optimizes for the case of accidentally showing extra information that a user can then investigate and disable, rather than hiding information that the user might not realize is missing.
Sorry for the late reply, I've been struggling to decide what the correct behaviour is here. I think I'm convinced that the flag in #60 is the correct behaviour, I'll probably release it with a major version bump since it is technically a breaking change. I'm still pondering on the feature flag name - |
Short: I agree "anyhow" isn't great. Something implementation hinting like Long: What I mean by that is
It seems slightly odd that we emit the error source only when I reached for "anyhow" as it conveyed less implementation detail, and more user intent, but I also agree that if no one uses "anyhow" in 5 years, it would become an anachronism (or a Skeuomorph like the using a floppy as the save icon). For naming problems (a historically difficult thing in computer science), I like to come up with as many possible combinations as possible. In brainstorming, quantity has a quality all of its own. Behavior:
Literal implications:
Esoteric:
I'm open to other ideas. A thesaurus can help inspire variations as well. I'm still leaning towards the "behavior" category as it gives us a little room to adjust implementation decisions if needed in the future. I like "caused by" as that's how the end user will experience a difference (and pulling from language used in the current readme). I'm trying to talk through my thought process, ultimately you're the maintainer and I'll go with whatever you decide. Edit: Had a moment of Semantic satiation and accidentally swapped "caused" with "called" in my original post. I just fixed it. |
close andrewhickman#59 Changes the default behavior so that the output in the readme now matches the output a user would see when they use the library. Specifically, it now includes the original `std::io::Error` in the output. It introduces a feature `anyhow`. By default: - By default: fs-err will include `std::io::Error` in the Display output, and return `None` from `Error::source()` - With `anyhow` fs-err will not include std::io::Error in the Display output, and return `Some(std::io::Error)` from `Error::source()` This is based on the guidance from andrewhickman#51. That discussion links to this 2020 discussion rust-lang/project-error-handling#23 that suggests that you should either print the source and return `None` from `Error::source()` (https://doc.rust-lang.org/std/error/trait.Error.html#method.source) or not print anything and return `Some(E)`. This allows users of anyhow (or similar) libraries to configure fs-err for the behavior they desire, while not hiding information by default from unsuspecting adopters that are not using those libraries. It optimizes for the case of accidentally showing extra information that a user can then investigate and disable, rather than hiding information that the user might not realize is missing.
I discussed the logic here andrewhickman#59 (comment). The prior suggested name "anyhow" was a little too specific/esoteric and in the event that the feature flag outlives the popularity of `anyhow` it wouldn't make sense. This suggested name tries to focus on the behavior outcome of the feature. It empowers callers to format the "called by" information however they want by: - Providing a source of that data (Error::source) - Not formatting emitting that data in `Display`
close andrewhickman#59 Changes the default behavior so that the output in the readme now matches the output a user would see when they use the library. Specifically, it now includes the original `std::io::Error` in the output. It introduces a feature `anyhow`. By default: - By default: fs-err will include `std::io::Error` in the Display output, and return `None` from `Error::source()` - With `anyhow` fs-err will not include std::io::Error in the Display output, and return `Some(std::io::Error)` from `Error::source()` This is based on the guidance from andrewhickman#51. That discussion links to this 2020 discussion rust-lang/project-error-handling#23 that suggests that you should either print the source and return `None` from `Error::source()` (https://doc.rust-lang.org/std/error/trait.Error.html#method.source) or not print anything and return `Some(E)`. This allows users of anyhow (or similar) libraries to configure fs-err for the behavior they desire, while not hiding information by default from unsuspecting adopters that are not using those libraries. It optimizes for the case of accidentally showing extra information that a user can then investigate and disable, rather than hiding information that the user might not realize is missing.
I discussed the logic here andrewhickman#59 (comment). The prior suggested name "anyhow" was a little too specific/esoteric and in the event that the feature flag outlives the popularity of `anyhow` it wouldn't make sense. This suggested name tries to focus on the behavior outcome of the feature. It empowers callers to format the "called by" information however they want by: - Providing a source of that data (Error::source) - Not formatting emitting that data in `Display`
I marked #60 as ready for review |
* Show source by default, add feature to hide it close #59 Changes the default behavior so that the output in the readme now matches the output a user would see when they use the library. Specifically, it now includes the original `std::io::Error` in the output. It introduces a feature `anyhow`. By default: - By default: fs-err will include `std::io::Error` in the Display output, and return `None` from `Error::source()` - With `anyhow` fs-err will not include std::io::Error in the Display output, and return `Some(std::io::Error)` from `Error::source()` This is based on the guidance from #51. That discussion links to this 2020 discussion rust-lang/project-error-handling#23 that suggests that you should either print the source and return `None` from `Error::source()` (https://doc.rust-lang.org/std/error/trait.Error.html#method.source) or not print anything and return `Some(E)`. This allows users of anyhow (or similar) libraries to configure fs-err for the behavior they desire, while not hiding information by default from unsuspecting adopters that are not using those libraries. It optimizes for the case of accidentally showing extra information that a user can then investigate and disable, rather than hiding information that the user might not realize is missing. * Update feature name I discussed the logic here #59 (comment). The prior suggested name "anyhow" was a little too specific/esoteric and in the event that the feature flag outlives the popularity of `anyhow` it wouldn't make sense. This suggested name tries to focus on the behavior outcome of the feature. It empowers callers to format the "called by" information however they want by: - Providing a source of that data (Error::source) - Not formatting emitting that data in `Display` * Update feature name to `expose_original_error` * Document why that feature disables displaying error At a glance it's not clear why that logic exists based solely on the feature name. Adding a doc here clarifies the intent.
#60 is released in version 3.0.0 🥳 |
Hi! Thank you for this crate.
I recently tried migrating one of my projects from
fs
tofs-err
.Given the README says:
...and then gives examples like:
...I was expecting the error messages to include additional information out of the box, and for their display representation to look like the above.
However, I found that it actually made our project's user-facing error messages worse in many cases (for an example, see heroku/buildpacks-python#270), since the underlying cause is no longer printed, and now only the operation and filename was. Printing the debug representation showed the underlying error existed, but under
source
.Searching for the
caused by
line shown in the README examples, I found it didn't originate in the display representation infs-err
, but instead is a feature of e.g.anyhow
:https://github.com/dtolnay/anyhow/blob/afe93e7b167d069ac79f2c7f363b919d3793e6ce/src/fmt.rs#L30
This was surprising, since
anyhow
isn't mentioned in the README.I was going to file a bug/feature request about including
source
in the top-level error's display representation, however, found #51 which suggests not including it is by design.I get the reasoning in that issue (so I'm not necessarily suggesting the
fs-err
behaviour should be changed), however, this meansfs-err
isn't quite the drop-in replacement it says it is, and at the very least, I think the README should mention that consumers need to adjust their error logging to print the errorsource
too, if they are not using a library that does it for them (like anyhow).The text was updated successfully, but these errors were encountered: