1# An Error and ErrorKind pair
2
3This pattern is the most robust way to manage errors - and also the most high
4maintenance. It combines some of the advantages of the [using Error][use-error]
5pattern and the [custom failure][custom-fail] patterns, while avoiding some of
6the disadvantages each of those patterns has:
7
81. Like `Error`, this is forward compatible with new underlying kinds of
9errors from your dependencies.
102. Like custom failures, this pattern allows you to specify additional information about the error that your dependencies don't give you.
113. Like `Error`, it can be easier to convert underlying errors from dependency
12into this type than for custom failures.
134. Like custom failures, users can gain some information about the error
14without downcasting.
15
16The pattern is to create two new failure types: an `Error` and an `ErrorKind`,
17and to leverage [the `Context` type][context-api] provided by failure.
18
19```rust
20#[derive(Debug)]
21struct MyError {
22    inner: Context<MyErrorKind>,
23}
24
25#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)]
26enum MyErrorKind {
27    // A plain enum with no data in any of its variants
28    //
29    // For example:
30    #[fail(display = "A contextual error message.")]
31    OneVariant,
32    // ...
33}
34```
35
36Unfortunately, it is not easy to correctly derive `Fail` for `MyError` so that
37it delegates things to its inner `Context`. You should write those impls
38yourself:
39
40```rust
41impl Fail for MyError {
42    fn name(&self) -> Option<&str> {
43        self.inner.name()
44    }
45
46    fn cause(&self) -> Option<&Fail> {
47        self.inner.cause()
48    }
49
50    fn backtrace(&self) -> Option<&Backtrace> {
51        self.inner.backtrace()
52    }
53}
54
55impl Display for MyError {
56    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57        Display::fmt(&self.inner, f)
58    }
59}
60```
61
62You should also provide some conversions and accessors, to go between a
63Context, your ErrorKind, and your Error:
64
65```rust
66impl MyError {
67    pub fn kind(&self) -> MyErrorKind {
68        *self.inner.get_context()
69    }
70}
71
72impl From<MyErrorKind> for MyError {
73    fn from(kind: MyErrorKind) -> MyError {
74        MyError { inner: Context::new(kind) }
75    }
76}
77
78impl From<Context<MyErrorKind>> for MyError {
79    fn from(inner: Context<MyErrorKind>) -> MyError {
80        MyError { inner: inner }
81    }
82}
83```
84
85With this code set up, you can use the context method from failure to apply
86your ErrorKind to `Result`s in underlying libraries:
87
88```rust
89use failure::ResultExt;
90perform_some_io().context(ErrorKind::NetworkFailure)?;
91```
92
93You can also directly throw `ErrorKind` without an underlying error when
94appropriate:
95
96```rust
97Err(ErrorKind::DomainSpecificError)?
98```
99
100### What should your ErrorKind contain?
101
102Your error kind probably should not carry data - and if it does, it should only
103carry stateless data types that provide additional information about what the
104`ErrorKind` means. This way, your `ErrorKind` can be `Eq`, making it
105easy to use as a way of comparing errors.
106
107Your ErrorKind is a way of providing information about what errors mean
108appropriate to the level of abstraction that your library operates at. As some
109examples:
110
111- If your library expects to read from the user's `Cargo.toml`, you might have
112  a `InvalidCargoToml` variant, to capture what `io::Error` and `toml::Error`
113  mean in the context of your library.
114- If your library does both file system activity and network activity, you
115  might have `Filesystem` and `Network` variants, to divide up the `io::Error`s
116  between which system in particular failed.
117
118Exactly what semantic information is appropriate depends entirely on what this
119bit of code is intended to do.
120
121## When might you use this pattern?
122
123The most likely use cases for this pattern are mid-layer which perform a
124function that requires many dependencies, and that are intended to be used in
125production. Libraries with few dependencies do not need to manage many
126underlying error types and can probably suffice with a simpler [custom
127failure][custom-fail]. Applications that know they are almost always just going
128to log these errors can get away with [using the Error type][use-error] rather
129than managing extra context information.
130
131That said, when you need to provide the most expressive information about an
132error possible, this can be a good approach.
133
134## Caveats on this pattern
135
136This pattern is the most involved pattern documented in this book. It involves
137a lot of boilerplate to set up (which may be automated away eventually), and it
138requires you to apply a contextual message to every underlying error that is
139thrown inside your code. It can be a lot of work to maintain this pattern.
140
141Additionally, like the Error type, the Context type may use an allocation and a
142dynamic dispatch internally. If you know this is too expensive for your use
143case, you should not use this pattern.
144
145[use-error]: ./use-error.html
146[custom-fail]: ./custom-fail.html
147[context-api]: https://docs.rs/failure/latest/failure/struct.Context.html
148