dtolnay / thiserror

derive(Error) for struct and enum error types

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

backtrace() delegation

sergiimk opened this issue · comments

When wrapping one error that has a Backtrace with another error via #[from] without a backtrace field I'd expect outer error's Error::backtrace() method to return inner error's backtrace.

Example:

#![feature(backtrace)]

use std::backtrace::Backtrace;
use std::error::Error as StdError;
use std::fs::File;
use thiserror::Error;

#[derive(Error, Debug)]
enum MyErrorFoo {
    #[error("IO error: {source}")]
    IoError {
        #[from]
        source: std::io::Error,
        backtrace: Backtrace,
    },
}

#[derive(Error, Debug)]
enum MyErrorBar {
    #[error("Foo error: {0}")]
    FooError(#[from] MyErrorFoo),
}

fn foo() -> Result<(), MyErrorFoo> {
    File::open("/doesnt_exist")?;
    Ok(())
}

fn bar() -> Result<(), MyErrorBar> {
    foo()?;
    Ok(())
}

fn main() {
    let e_foo = foo().unwrap_err();
    assert!(e_foo.backtrace().is_some()); // PASSES

    let e_bar = bar().unwrap_err();
    match e_bar {
        MyErrorBar::FooError(ref inner) => assert!(inner.backtrace().is_some()), // PASSES
    };
    assert!(e_bar.backtrace().is_some()); // FAILS
}

I get same results when I tag backtrace field with #[backtrace] and when I tag FooError(#[from] MyErrorFoo) with #[transparent].

// PS: Thank you for a great library!

I might've been thinking the wrong way about this.

Rather than thinking of top-level error as a wrapper around the original error I should've been thinking of it as a chain of linked errors where some errors in the chain may have their own backtraces, so my error reporting code should not be relying on top-level's error's backtrace but rather should dig through this chain and pick which traces to display.

Appologies for confusion.