Skip to content

Error::source and Error::cause do not expose immediate error in custom io::Error #101817

Open
@jonhoo

Description

@jonhoo

I tried this code (playground):

use std::error::Error;

#[derive(Debug, PartialEq, Eq)]
struct E;

impl std::fmt::Display for E {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "E")
    }
}

impl Error for E {}

#[test]
fn custom_io_has_source() {
    let e = E;
    let e = std::io::Error::new(std::io::ErrorKind::Other, e);
    assert_eq!(e.source().and_then(|s| s.downcast_ref::<E>()), Some(&E));
}

I expected to see this happen: the test passed

Instead, this happened: the test failed with

thread 'custom_io_has_source' panicked at 'assertion failed: `(left == right)`
  left: `None`,
 right: `Some(E)`', src/lib.rs:18:5

I don't believe this is intentional, since the code standard library impl Error for io::Error specifically has:

ErrorData::Custom(c) => c.error.source(),

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 between io::Error's .source() and .downcast().

assert_eq!(e.downcast::<E>().unwrap(), Box::new(E));

Meta

rustc --version --verbose:

rustc 1.63.0 (4b91a6ea7 2022-08-08)
binary: rustc
commit-hash: 4b91a6ea7258a947e59c6522cd5898e7c0a6a88f
commit-date: 2022-08-08
host: aarch64-unknown-linux-gnu
release: 1.63.0
LLVM version: 14.0.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-error-handlingArea: Error handlingC-bugCategory: This is a bug.T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions