Deriving Fail

Though you can implement Fail yourself, we also provide a derive macro to generate the impl for you. To get access to this macro, you must tag the extern crate declaration with #[macro_use], as in:

#[macro_use] extern crate failure;

In its smallest form, deriving Fail looks like this:

#[macro_use] extern crate failure;

use std::fmt;

#[derive(Fail, Debug)]
struct MyError;

impl fmt::Display for MyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "An error occurred.")
    }
}

All failures need to implement Display, so we have added an impl of Display. However, implementing Display is much more boilerplate than implementing Fail - this is why we support deriving Display for you.

Deriving Display

You can derive an implementation of Display with a special attribute:

#[macro_use] extern crate failure;

#[derive(Fail, Debug)]
#[fail(display = "An error occurred.")]
struct MyError;

This attribute will cause the Fail derive to also generate an impl of Display, so that you don't have to implement one yourself.

String interpolation

String literals are not enough for error messages in many cases. Often, you want to include parts of the error value interpolated into the message. You can do this with failure using the same string interpolation syntax as Rust's formatting and printing macros:

#[macro_use] extern crate failure;

#[derive(Fail, Debug)]
#[fail(display = "An error occurred with error code {}. ({})", code, message)]
struct MyError {
    code: i32,
    message: String,
}

Note that unlike code that would appear in a method, this does not use something like self.code or self.message; it just uses the field names directly. This is because of a limitation in Rust's current attribute syntax. As a result, you can only interpolate fields through the derivation; you cannot perform method calls or use other arbitrary expressions.

Tuple structs

With regular structs, you can use the name of the field in string interpolation. When deriving Fail for a tuple struct, you might expect to use the numeric index to refer to fields 0, 1, et cetera. However, a compiler limitation prevents this from parsing today.

For the time being, tuple field accesses in the display attribute need to be prefixed with an underscore:

#[macro_use] extern crate failure;

#[derive(Fail, Debug)]
#[fail(display = "An error occurred with error code {}.", _0)]
struct MyError(i32);


#[derive(Fail, Debug)]
#[fail(display = "An error occurred with error code {} ({}).", _0, _1)]
struct MyOtherError(i32, String);

Enums

Implementing Display is also supported for enums by applying the attribute to each variant of the enum, rather than to the enum as a whole. The Display impl will match over the enum to generate the correct error message. For example:

#[macro_use] extern crate failure;

#[derive(Fail, Debug)]
enum MyError {
    #[fail(display = "{} is not a valid version.", _0)]
    InvalidVersion(u32),
    #[fail(display = "IO error: {}", error)]
    IoError { error: io::Error },
    #[fail(display = "An unknown error has occurred.")]
    UnknownError,
}

Overriding backtrace

The backtrace method will be automatically overridden if the type contains a field with the type Backtrace. This works for both structs and enums.

#[macro_use] extern crate failure;

use failure::Backtrace;

/// MyError::backtrace will return a reference to the backtrace field
#[derive(Fail, Debug)]
#[fail(display = "An error occurred.")]
struct MyError {
    backtrace: Backtrace,
}

/// MyEnumError::backtrace will return a reference to the backtrace only if it
/// is Variant2, otherwise it will return None.
#[derive(Fail, Debug)]
enum MyEnumError {
    #[fail(display = "An error occurred.")]
    Variant1,
    #[fail(display = "A different error occurred.")]
    Variant2(Backtrace),
}

This happens automatically; no other annotations are necessary. It only works if the type is named Backtrace, and not if you have created an alias for the Backtrace type.

Overriding cause

In contrast to backtrace, the cause cannot be determined by type name alone because it could be any type which implements Fail. For this reason, if your error has an underlying cause field, you need to annotate that field with the #[fail(cause)] attribute.

This can be used in fields of enums as well as structs.

#[macro_use] extern crate failure;

use std::io;

/// MyError::cause will return a reference to the io_error field
#[derive(Fail, Debug)]
#[fail(display = "An error occurred.")]
struct MyError {
    #[fail(cause)] io_error: io::Error,
}

/// MyEnumError::cause will return a reference only if it is Variant2,
/// otherwise it will return None.
#[derive(Fail, Debug)]
enum MyEnumError {
    #[fail(display = "An error occurred.")]
    Variant1,
    #[fail(display = "A different error occurred.")]
    Variant2(#[fail(cause)] io::Error),
}