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