Skip to content
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

Wrapping anyhow::Error in another error loses backtrace #174

Open
Ten16 opened this issue Jun 14, 2022 · 1 comment
Open

Wrapping anyhow::Error in another error loses backtrace #174

Ten16 opened this issue Jun 14, 2022 · 1 comment

Comments

@Ten16
Copy link

Ten16 commented Jun 14, 2022

Migrating from failure to anyhow, I encounter an issue where I start losing backtraces when anyhow::Errors are wrapped in another error type:

#[test]
fn backtrace_preserved_after_thiserror_derive() {
	#[derive(Debug, thiserror::Error)]
	pub enum SomeError {
		#[error(transparent)]
		Anyhow(anyhow::Error),
	}

	let mut errs = (0..2).map(|_| anyhow::anyhow!("aaa"));

	let wrapped = anyhow::Error::from(SomeError::Anyhow(errs.next().unwrap()));
	let notwrapped = errs.next().unwrap();

	assert_eq!(wrapped.backtrace().to_string(), notwrapped.backtrace().to_string());
}

It is a kind of usage suggested by the documentation:

thiserror/src/lib.rs

Lines 194 to 195 in 799b3d3

//! #[error(transparent)]
//! Other(#[from] anyhow::Error), // source and Display delegate to anyhow::Error

It used to be possible to work around this issue in failure (even on stable, which we are on).
It would seem fine if the backtrace could only be propagated if coming from anyhow.

Is it possible to achieve something like this with the anyhow/thiserror combination?

@mhnap
Copy link

mhnap commented Aug 28, 2024

I found one solution for this problem - add the #[backtrace] attribute to inner anyhow::Error, but it requires a nightly.

By the way, map() is lazy and your test never will pass as there indeed would be two different backtraces generated during next() call. I fixed it by switching to Vec.

#[test]
fn backtrace_preserved_after_thiserror_derive() {
    #[derive(Debug, thiserror::Error)]
    enum SomeError {
        #[error(transparent)]
        Anyhow {
            #[backtrace] // <-- Passing with this attribute
            source: anyhow::Error,
        },
    }

    let mut errs: Vec<_> = (0..2).map(|_| anyhow::anyhow!("aaa")).collect();

    let wrapped = anyhow::Error::from(SomeError::Anyhow {
        source: errs.pop().unwrap(),
    });
    let notwrapped = errs.pop().unwrap();

    assert_eq!(
        wrapped.backtrace().to_string(),
        notwrapped.backtrace().to_string()
    );
}

Would be great if this could be solved on stable too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants