1# The `Fail` trait
2
3The `Fail` trait is a replacement for [`std::error::Error`][stderror]. It has
4been designed to support a number of operations:
5
6- Because it is bound by both `Debug` and `Display`, any failure can be
7  printed in two ways.
8- It has both a `backtrace` and a `cause` method, allowing users to get
9  information about how the error occurred.
10- It supports wrapping failures in additional contextual information.
11- Because it is bound by `Send` and `Sync`, failures can be moved and shared
12  between threads easily.
13- Because it is bound by `'static`, the abstract `Fail` trait object can be
14  downcast into concrete types.
15
16Every new error type in your code should implement `Fail`, so it can be
17integrated into the entire system built around this trait. You can manually
18implement `Fail` yourself, or you can use the derive for `Fail` defined
19in a separate crate and documented [here][derive-docs].
20
21Implementors of this trait are called 'failures'.
22
23## Cause
24
25Often, an error type contains (or could contain) another underlying error type
26which represents the "cause" of this error - for example, if your custom error
27contains an `io::Error`, that is the cause of your error.
28
29The cause method on the `Fail` trait allows all errors to expose their underlying
30cause - if they have one - in a consistent way. Users can loop over the chain
31of causes, for example, getting the entire series of causes for an error:
32
33```rust
34// Assume err is a type that implements `Fail`
35let mut fail: &Fail = err;
36
37while let Some(cause) = fail.cause() {
38    println!("{}", cause);
39
40    // Make `fail` the reference to the cause of the previous fail, making the
41    // loop "dig deeper" into the cause chain.
42    fail = cause;
43}
44```
45
46Because `&Fail` supports downcasting, you can also inspect causes in more
47detail if you are expecting a certain failure:
48
49```rust
50while let Some(cause) = fail.cause() {
51
52    if let Some(err) = cause.downcast_ref::<io::Error>() {
53        // treat io::Error specially
54    } else {
55        // fallback case
56    }
57
58    fail = cause;
59}
60```
61
62For convenience an iterator is also provided:
63
64```rust
65// Assume err is a type that implements `Fail`
66let mut fail: &Fail = err;
67
68for cause in fail.iter_causes() {
69    println!("{}", cause);
70}
71```
72
73## Backtraces
74
75Errors can also generate a backtrace when they are constructed, helping you
76determine the place the error was generated and the function chain that called into
77that. Like causes, this is entirely optional - the authors of each failure
78have to decide if generating a backtrace is appropriate in their use case.
79
80The backtrace method allows all errors to expose their backtrace if they have
81one. This enables a consistent method for getting the backtrace from an error:
82
83```rust
84// We don't even know the type of the cause, but we can still get its
85// backtrace.
86if let Some(bt) = err.cause().and_then(|cause| cause.backtrace()) {
87    println!("{}", bt)
88}
89```
90
91The `Backtrace` type exposed by `failure` is different from the `Backtrace` exposed
92by the [backtrace crate][backtrace-crate], in that it has several optimizations:
93
94- It has a `no_std` compatible form which will never be generated (because
95  backtraces require heap allocation), and should be entirely compiled out.
96- It will not be generated unless the `RUST_BACKTRACE` environment variable has
97  been set at runtime.
98- Symbol resolution is delayed until the backtrace is actually printed, because
99  this is the most expensive part of generating a backtrace.
100
101## Context
102
103Often, the libraries you are using will present error messages that don't
104provide very helpful information about what exactly has gone wrong. For
105example, if an `io::Error` says that an entity was "Not Found," that doesn't
106communicate much about what specific file was missing - if it even was a file
107(as opposed to a directory for example).
108
109You can inject additional context to be carried with this error value,
110providing semantic information about the nature of the error appropriate to the
111level of abstraction that the code you are writing operates at. The `context`
112method on `Fail` takes any displayable value (such as a string) to act as
113context for this error.
114
115Using the `ResultExt` trait, you can also get `context` as a convenient method on
116`Result` directly. For example, suppose that your code attempted to read from a
117Cargo.toml. You can wrap the `io::Error`s that occur with additional context
118about what operation has failed:
119
120```rust
121use failure::ResultExt;
122
123let mut file = File::open(cargo_toml_path).context("Missing Cargo.toml")?;
124file.read_to_end(&buffer).context("Could not read Cargo.toml")?;
125```
126
127The `Context` object also has a constructor that does not take an underlying
128error, allowing you to create ad hoc Context errors alongside those created by
129applying the `context` method to an underlying error.
130
131## Backwards compatibility
132
133We've taken several steps to make transitioning from `std::error` to `failure` as
134painless as possible.
135
136First, there is a blanket implementation of `Fail` for all types that implement
137`std::error::Error`, as long as they are `Send + Sync + 'static`. If you are
138dealing with a library that hasn't shifted to `Fail`, it is automatically
139compatible with `failure` already.
140
141Second, `Fail` contains a method called `compat`, which produces a type that
142implements `std::error::Error`. If you have a type that implements `Fail`, but
143not the older `Error` trait, you can call `compat` to get a type that does
144implement that trait (for example, if you need to return a `Box<Error>`).
145
146The biggest hole in our backwards compatibility story is that you cannot
147implement `std::error::Error` and also override the backtrace and cause methods
148on `Fail`. We intend to enable this with specialization when it becomes stable.
149
150[derive-docs]: ./derive-fail.html
151[stderror]: https://doc.rust-lang.org/std/error/trait.Error.html
152[backtrace-crate]: http://alexcrichton.com/backtrace-rs
153