failure icon indicating copy to clipboard operation
failure copied to clipboard

Clarify lack of `backtrace` and `cause` on custom fail types

Open epage opened this issue 8 years ago • 7 comments

Maybe its from having come from error-chain where too much magic is happening but I feel the documentation obscures the fact that custom Fails will not have a backtrace or cause.

Two simple ways to improve this

  • In "Deriving Fail", rename "Overriding backtrace" and "Overriding cause" to "Including a backtrace" and "Including a cause".
    • While "overriding" is technically correct, it assumes knowledge of the library.
  • In "A Custom Fail Type" provide include commentary about backtrace and cause

epage avatar Nov 17 '17 00:11 epage

I'm personally struggling with how to add context to an Error while retaining the original cause. With error-chain I would just use chain_err.

euclio avatar Nov 30 '17 01:11 euclio

@euclio The analog to chain_err is context, which does implement cause. What are you worried you're not retaining?

withoutboats avatar Nov 30 '17 01:11 withoutboats

Perhaps I'm not understanding what's going on, but with the following code

extern crate failure;

use failure::{Error, ResultExt};

fn error1() -> Result<(), Error> { Ok(()) }

fn error2() -> Result<(), Error> { Err(failure::err_msg("err")) }

fn run() -> Result<(), Error> {
  error1().context("failed because 1")?;
  error2().context("failed because 2")?;
  Ok(())
}

fn main() {
    if let Err(e) = run() {
        let mut fail = e.cause();
        while let Some(cause) = fail.cause() {
            println!("cause: {}", fail);
            fail = cause;
        }
    }
}

I would expect it to print

cause: failed because 2
cause: err

but it only prints

cause: failed because 2

euclio avatar Nov 30 '17 01:11 euclio

@euclio This looks like a bug in Context's cause method, let me investigate.

withoutboats avatar Nov 30 '17 01:11 withoutboats

@euclio Oh, its actually an error in your while loop logic. Your while loop short circuits when there is no underlying error, meaning it doesn't print the final ("root cause") error. Essentially an off by one error.

Here's one way of writing this loop without the error:

let mut fail = Some(e.cause());
while let Some(cause) = cause {
     println!("cause: {}", cause):
     fail = cause.cause():
}

Fortunately the 0.1.1 version (hoping to release tomorrow) will have a causes iterator which should make this all simpler:

for cause in e.causes() {
    println!("cause: {}", cause):
}

withoutboats avatar Nov 30 '17 02:11 withoutboats

Shouldn't this issue be closed?

otavio avatar Feb 22 '18 11:02 otavio

It would be nice to rename "Overriding backtrace", this was a tripping point for me.

joelgallant avatar Feb 10 '19 23:02 joelgallant