-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Error::source and Error::cause do not expose immediate error in custom io::Error #101817
Comments
This happens because in https://github.com/rust-lang/rust/blob/master/library/std/src/io/error.rs#L954 we return I agree this is kind of confusing, and probably semantically wrong. |
I'm in favor of changing it in principal, but it has the chance to break a lot of people's code, and only in an error-handling path which may not have good test coverage (although, perhaps the code would be made to work, since this is the way they assumed it would behave...) |
I thought that for a second too, but I don't think that's right either, since I also get use std::error::Error;
#[derive(Debug, PartialEq, Eq)]
struct E;
static E2: E = E;
impl std::fmt::Display for E {
fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result {
write!(f, "E")
}
}
impl Error for E {
fn description(&self) -> &'static str {
"E"
}
fn cause(&self) -> Option<&Error> {
Some(&E2)
}
}
#[test]
fn custom_io_has_source() {
let e = E;
let e = std::io::Error::new(std::io::ErrorKind::Other, e);
assert!(e.cause().is_some());
} |
Ah, wait, no, never mind, I was still testing with Rust 1.0! Yes, on newer Rust versions I do get the return value from the inner error's |
Fixing this has the issue that it means displaying every error in the cause chain will make it appear that this error is hit twice. That seems undesirable to me. |
Because That said, I think it's quite important to retain the full error chain through |
You should be able to use |
True, though that won't work with anything that expects to be able to walk the error chain solely through |
I just realized the rustls situation I ran into is even worse because multiple layers in the hyper TLS stack end up converting their errors through
Note the nested |
Yeah, I agree it seems weird and isn't ideal. I'm not sure there's an ideal fix though -- it's quite common IME for people to print out the But yeah, the alternative is that it's very tricky and subtle to walk the error chain looking for a specific error. |
I suppose it might be possible to change But it feels unfortunate to have this foot-gun here for anything that wants to implement error walking to work around. |
vendoring this here for visibility, I replied to the PR that was opened associated with this issue: #101818 (comment) |
I tried this code (playground):
I expected to see this happen: the test passed
Instead, this happened: the test failed with
I don't believe this is intentional, since the code standard library
impl Error for io::Error
specifically has:rust/library/std/src/io/error.rs
Line 963 in a926696
In fact, it was specifically implemented in #58963, but that PR doesn't appear to have included any tests. The test above fails even on 1.30.0 (which is the first Rust version with
fn source
).What's even more interesting is that
assert!(e.cause().is_some())
fails all the way back to Rust 1.0, so it sure seems like something is fishy here.I wonder if @thomcc may know how the source might be disappearing given his work in #87869?
Another interesting tidbit here is that using
io_error_downcast
we do get the inner error, meaning there will (when that feature lands) be a discrepancy betweenio::Error
's.source()
and.downcast()
.Meta
rustc --version --verbose
:The text was updated successfully, but these errors were encountered: