# Simplify error handling

**URL:** <https://internals.rust-lang.org/t/simplify-error-handling/12226>\
**Category:** language design\
**Created:** [April 24, 2020, 4:12pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226 "2020-04-24T16:12:00Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![redradist](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/redradist/32/6475_2.png) [@redradist](https://internals.rust-lang.org/u/redradist)\
**Post date:** [April 24, 2020, 4:12pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/1 "2020-04-24T16:12:00Z")

</div>

Consider the following code:

```rust
enum MyError {
    Io(io::Error),
    Parser(num::ParseIntError)
}

use crate::MyError::{Io, Parser};

impl From<std::io::Error> for MyError {
    fn from(err: std::io::Error) -> Self {
        Io(err)
    }
}

impl From<num::ParseIntError> for MyError {
    fn from(err: num::ParseIntError) -> Self {
        Parser(err)
    }
}

fn get_file(s: &str) -> Result<File, io::Error> {
    let file = File::open("sdasfsadas")?;
    Ok(file)
}

fn parse_int(file: &File) -> Result<u32, num::ParseIntError> {
    Ok(2u32)
}

fn handle_file(s: &str) -> Result<u32, MyError> {
    let file = get_file(s)?;
    let int = parse_int(&file)?;
    Ok(int)
}

```

As we can see there are lots of boilerplate code !!

Let's simplify it:

```rust
/// Auto generated code
/// enum MyError {
/// Io(io::Error),
/// Parser(num::ParseIntError)
/// }
/// 
/// use crate::MyError::{Io, Parser};
/// 
/// impl From<std::io::Error> for MyError {
/// fn from(err: std::io::Error) -> Self {
/// Io(err)
/// }
/// }
/// 
/// impl From<num::ParseIntError> for MyError {
/// fn from(err: num::ParseIntError) -> Self {
/// Parser(err)
/// }
/// }

fn get_file(s: &str) -> File throws { // Auto generated result Result<u32, io::Error>
    let file = File::open("sdasfsadas")?;
    Ok(file)
}

fn parse_int(file: &File) -> u32 throws num::ParseIntError { // Auto generated result Result<u32, num::ParseIntError>
    Ok(2u32)
}

fn handle_file(s: &str) -> u32 throws { // Auto generated result Result<u32, MyError> and enum MyError
    let file = get_file(s)?;
    let int = parse_int(&file)?;
    Ok(int)
}

```

It is possible also to specify errors manually:

```rust
fn get_file(s: &str) -> File throws io::Error { // Auto generated result Result<u32, io::Error>
    let file = File::open("sdasfsadas")?;
    Ok(file)
}

fn parse_int(file: &File) -> u32 throws num::ParseIntError { // Auto generated result Result<u32, num::ParseIntError>
    Ok(2u32)
}

fn handle_file(s: &str) -> u32 throws io::Error, num::ParseIntError { // Auto generated result Result<u32, MyError> and enum MyError
    let file = get_file(s)?;
    let int = parse_int(&file)?;
    Ok(int)
}

```

When user specify one error after throws we should specify all errors

Also we could specify our own custom enum error MyError after throws keyword:

```rust
fn handle_file(s: &str) -> u32 throws MyError { // Auto generated result Result<u32, MyError>
    let file = get_file(s)?;
    let int = parse_int(&file)?;
    Ok(int)
}

```

In this case we should specify MyError manually as previously

Okay, let's look how the caller will handle result of `handle_file`:

```rust
fn handle_file(s: &str) -> u32 throws MyError { // Auto generated result Result<u32, MyError>
    let file = get_file(s)?;
    let int = parse_int(&file)?;
    Ok(int)
}

fn main() {
    let res = handle_file("some.txt");
    match res {
      Ok(res_code) => println!("res_code is {}", res_code),
      Err(IoError(err)) => println!("io_err is {}", err),
      Err(NumParserIntError(err)) => println!("parse_err is {}", err),
    };
}

```

This topic relate to:

> [@\[Pre-RFC\] Zero-overhead exceptions](https://internals.rust-lang.org/t/pre-rfc-zero-overhead-exceptions/11683):
>
> I would suggest to add Zero-Overhead Exception in Rust Consider the following code: union SomeFunctionMultipleError { err0: Error1, err1: Error2, } struct SomeFunctionFnError { index: u32, errors: SomeFunctionMultipleError, } fn some\_function(i: i32) -\> Result\<i32, SomeFunctionFnError\> { if i == 0 { Ok(2) } else if i == 1 { Err(SomeFunctionFnError{ index: 0, errors: SomeFunctionMultipleError {err1: Error1 {id0: 0, id1: 0, id3: 0}}}) } else { …

> <https://github.com/rust-lang/rfcs/pull/2441>
>
> \### \[🖼️ Rendered\](https://github.com/Centril/rfcs/blob/rfc/reserve-throw-fail/te…xt/0000-reserve-throw-fail.md)
> 
> \### 📝 Summary
> 
> Reserve \`throw\` and \`fail\` in edition 2018.
> 
> \### 🎵 Note
> 
> This RFC separates out the urgent question of keyword reservation from RFC #2426.
> It does not prescribe actually adding a \`fail expr\` or \`throw expr\` construct to the language.

It is also possible to handle multiple errors without introducing a new keyword and syntax, but instead by adding anonymous enum types:

```rust
fn get_file(s: &str) -> Result<u32, io::Error> {
    let file = File::open("sdasfsadas")?;
    Ok(file)
}

fn parse_int(file: &File) -> Result<u32, num::ParseIntError> {
    Ok(2u32)
}

fn handle_file(s: &str) -> Result<u32, io::Error | num::ParseIntError> { // Where io::Error | num::ParseIntError is auto generated anonymuos enum AnonymousEnumError
    let file = get_file(s)?;
    let int = parse_int(&file)?;
    Ok(int)
}

```

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [April 24, 2020, 4:26pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/2 "2020-04-24T16:26:58Z")

</div>

> [@redradist](#):
>
> enum MyError { Io(io::Error), Parser(num::ParseIntError) }

You can use [thiserror](https://docs.rs/thiserror/1.0.15/thiserror/) to get rid of most of the boiler plate, you only have to write out

```rust
#[derive(Error, Debug)]
enum MyError {
    #[error("io error")]
    Io(#[from] io::Error),
    #[error("integer parse error")]
    Parser(#[from] num::ParseIntError)
}

```

Which is pretty concise. (And it even generates a `Display` impl!)

---

<div class="post-metadata">

**Author:** ![redradist](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/redradist/32/6475_2.png) [@redradist](https://internals.rust-lang.org/u/redradist)\
**Post date:** [April 24, 2020, 4:31pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/3 "2020-04-24T16:31:47Z")

</div>

Yeah, thanks !! It is cool, I have not know such way ... But anyway from my point of view it is more readable either to auto-generate this enum or to specify all errors after throws keyword

It will have the following advantages:

1. More readable code
2. It will help people from other languages

Also it is point to discuss, maybe better would be to use fail keyword in such scenario ...

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [April 24, 2020, 4:35pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/4 "2020-04-24T16:35:24Z")

</div>

The advantage of using `thiserror` is;

- now you can specify the same error type across many functions
- it doesn't extend the language
- it generates `Display` impls

Using the same error type across many functions is pretty common, and if you omit the error type when there are lots of different error conditions (like in your first example) it becomes much harder to reason about what errors a function can yield (this makes it easier to accidentally break something).

---

<div class="post-metadata">

**Author:** ![redradist](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/redradist/32/6475_2.png) [@redradist](https://internals.rust-lang.org/u/redradist)\
**Post date:** [April 24, 2020, 4:46pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/5 "2020-04-24T16:46:55Z")

</div>

@RustyYatoYou wrote:

> > ```
> > now you can specify the same error type across many functions
> > 
> > ```

Compiler by itself could reuse in crate enums that have been generated and have the same structure !! Also it is possible to specify directly MyError after throws keyword and we will have the same usability

> > ```
> > it doesn't extend the language
> > 
> > ```

If we want to reduce boilerplate code it is necessary addition

> > ```
> > it generates Display impls
> > 
> > ```

General Result\<T, E\> also does not support Display impl !! It is not an issue

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [April 24, 2020, 4:54pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/6 "2020-04-24T16:54:10Z")

</div>

> [@redradist](#):
>
> Compiler by itself could reuse in crate enums that have been generated and have the same structure !! Also it is possible to specify directly MyError after throws keyword and we will have the same usability

Yes, but I'm worried about functions that need to return 4+ error sources (`io::Error`, `num::Parse*Error`, `some_lib::Error` ...), let's say your function has many such functions, you would need to either 1. invest in a common error type, 2. use error inference. I don't think that error inference would be desirable because it makes code much harder to read. Global type inference is _really bad_ for readability.

> [@redradist](#):
>
> If we want to reduce boilerplate code it is necessary addition

I think `thiserror` begs to differ. Minimal boilerplate without extending the language.

> [@redradist](#):
>
> General Result\<T, E\> also does not support Display impl !! It is not an issue

We would like to print/log errors when we encounter them. The fact that Result doesn't have a `Display` impl is irrelevant, because most of the time `T` won't be `Display`. (Note how `std::error::Error` requires `Display`)

---

<div class="post-metadata">

**Author:** ![Ixrec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ixrec/32/6754_2.png) [@Ixrec](https://internals.rust-lang.org/u/Ixrec)\
**Post date:** [April 24, 2020, 5:01pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/7 "2020-04-24T17:01:29Z")

</div>

It's probably worth mentioning that `thiserror` is only one in a long line of error type management crates. AFAIK the best 10,000-foot summary of where we're at in this space is:

[https://blog.yoshuawuyts.com/error-handling-survey/](https://blog.yoshuawuyts.com/error-handling-survey/)

As far as `throws` sugar, well, you linked to some of the past discussions yourself. There really is nothing new to say on that topic anymore 🙂

---

<div class="post-metadata">

**Author:** ![redradist](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/redradist/32/6475_2.png) [@redradist](https://internals.rust-lang.org/u/redradist)\
**Post date:** [April 24, 2020, 5:05pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/8 "2020-04-24T17:05:57Z")

</div>

> [@RustyYato](#):
>
> > [@redradist](#):
> >
> > Compiler by itself could reuse in crate enums that have been generated and have the same structure !! Also it is possible to specify directly MyError after throws keyword and we will have the same usability
> 
> Yes, but I'm worried about functions that need to return 4+ error sources (`io::Error`, `num::Parse*Error`, `some_lib::Error` ...), let's say your function has many such functions, you would need to either 1. invest in a common error type, 2. use error inference. I don't think that error inference would be desirable because it makes code much harder to read. Global type inference is _really bad_ for readability.

I do not think that it will make code less readable ... The reason I think so, because when we will read documentation to function rustdoc will autogenerate all errors inferenced after throws keyword

Also as first stage it is possible to implement just first solution for autogenerating enum MyError

Let's allow first of all the following code:

```rust
fn handle_file(s: &str) -> u32 throws io::Error, num::ParseIntError { // Auto generated result Result<u32, MyError> and enum MyError
    let file = get_file(s)?;
    let int = parse_int(&file)?;
    Ok(int)
}

```

It is also acceptable from my point of view, because it do not inforce user to write custom enum MyError

And if user what to specify custom enum error, it would be still possible the following code:

```rust
fn handle_file(s: &str) -> u32 throws MyError { // Auto generated result Result<u32, MyError> and enum MyError
    let file = get_file(s)?;
    let int = parse_int(&file)?;
    Ok(int)
}

```

We could leave inference for the future if it will be needed

---

<div class="post-metadata">

**Author:** ![redradist](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/redradist/32/6475_2.png) [@redradist](https://internals.rust-lang.org/u/redradist)\
**Post date:** [April 24, 2020, 5:09pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/9 "2020-04-24T17:09:41Z")

</div>

> [@Ixrec](#):
>
> It's probably worth mentioning that `thiserror` is only one in a long line of error type management crates. AFAIK the best 10,000-foot summary of where we're at in this space is:
> 
> [Error Handling Survey](https://blog.yoshuawuyts.com/error-handling-survey/)

So many crates prove that Rust does not provide general syntax for handling multiple errors

---

<div class="post-metadata">

**Author:** ![Ixrec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ixrec/32/6754_2.png) [@Ixrec](https://internals.rust-lang.org/u/Ixrec)\
**Post date:** [April 24, 2020, 5:12pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/10 "2020-04-24T17:12:50Z")

</div>

> [@redradist](#):
>
> So many crates prove that Rust does not provide general syntax for handling multiple errors

Well... tautologically, yes? That doesn't automatically mean we need core language syntax for this. These crates' APIs are already awfully concise.

Admittedly you seem to be widening the scope of this thread to include not just error type management, but also most of if not all of Ok-wrapping, `try`/`throws`/etc sugar proposals, anonymous enums and enum impl Trait. All of which have been several threads of their own already, so I'll stop here until there's a more specific question.

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [April 24, 2020, 5:13pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/11 "2020-04-24T17:13:12Z")

</div>

You have completely missed the point. For small functions with 2 error types, yes it does seem better, but **it does not scale**. For example, if you need to add an error condition to a function, then you will need to change _every_ function that calls that function, potentially breaking downstream crates. With a common error type, you just need to add a variant (and with `#[non_exhaustive]`, it doesn't even have to be a breaking change).

I think that the `throws` syntax is actively harmful, because it makes it easier to do the lazy thing which could lead to breakage, and unmaintainable code in the future.

~~If `throws` is just an alias for `Result`, then there is no point to it.~~

---

<div class="post-metadata">

**Author:** ![redradist](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/redradist/32/6475_2.png) [@redradist](https://internals.rust-lang.org/u/redradist)\
**Post date:** [April 24, 2020, 5:49pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/12 "2020-04-24T17:49:53Z")

</div>

> [@RustyYato](#):
>
> If `throws` is just an alias for `Result`, then there is no point to it.

`throws` keyword is an alias for `Result<T, E>` for generating `E` custom error such as MyError:

```rust
enum MyError {
    Io(io::Error),
    Parser(num::ParseIntError)
}

```

And it is needed to reduce boilerplate code

---

<div class="post-metadata">

**Author:** ![Ixrec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ixrec/32/6754_2.png) [@Ixrec](https://internals.rust-lang.org/u/Ixrec)\
**Post date:** [April 24, 2020, 6:06pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/13 "2020-04-24T18:06:04Z")

</div>

So far this sounds like an "anonymous enums" proposal. I believe [https://github.com/rust-lang/rfcs/pull/2587](https://github.com/rust-lang/rfcs/pull/2587) was the last serious attempt at something like this.

This is also following the weirdly standard pattern for such suggestions by forgetting to describe what `match`ing on one of these autogenerated/anonymous enums would look like, which is usually where these proposals get bogged down in unpleasantness.

How would you write the client code calling one of these `throws` functions?

---

<div class="post-metadata">

**Author:** ![Aloso](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aloso/32/5039_2.png) [@Aloso](https://internals.rust-lang.org/u/Aloso)\
**Post date:** [April 24, 2020, 6:14pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/14 "2020-04-24T18:14:08Z")

</div>

I agree with @RustyYato here. There are two different ways to implement this proposal, and both have serious flaws:

1. Sweep all dependencies and accumulate all possible error values that can be returned from a function with the `throws` keyword, into a huge enum.

2. Auto-generate one error enum for each function with the `throws` keyword and at least two error types. Functions with the same set of error types can share the same auto-generated error enum; conversions between error types are auto-implemented where necessary.

However, if you only allow the explicit version, this would be less problematic:

```rust
fn foo() -> u32 throws io::Error, num::ParseIntError; // okay
fn foo() -> u32 throws; // forbidden!

```

The only remaining problem is, how do we pattern match on this auto-generated type?

An alternative would be anonymous enums that automatically coerce into their supersets:

```rust
fn handle_file(s: &str) -> Result<u32, io::Error | num::ParseIntError> {
    let content = std::fs::read_to_string(s)?;
    let int: u32 = content.parse()?;
    Ok(int)
}

match handle_file("") {
    Ok(n) => n,
    Err(e @ io::Error) => todo!(),
    Err(e @ num::ParseIntError) => todo!(),
}

```

Anonymous enums have been [proposed before](https://users.rust-lang.org/t/anonymous-enums/5478).

---

<div class="post-metadata">

**Author:** ![redradist](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/redradist/32/6475_2.png) [@redradist](https://internals.rust-lang.org/u/redradist)\
**Post date:** [April 24, 2020, 6:41pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/15 "2020-04-24T18:41:27Z")

</div>

> [@Ixrec](#):
>
> So far this sounds like an "anonymous enums" proposal. I believe [https://github.com/rust-lang/rfcs/pull/2587](https://github.com/rust-lang/rfcs/pull/2587) was the last serious attempt at something like this.
> 
> This is also following the weirdly standard pattern for such suggestions by forgetting to describe what `match`ing on one of these autogenerated/anonymous enums would look like, which is usually where these proposals get bogged down in unpleasantness.
> 
> How would you write the client code calling one of these `throws` functions?

Okay, lets look at the following example:

```rust
fn handle_file(s: &str) -> u32 throws io::Error, num::ParseIntError { // Auto generated result Result<u32, MyError>
    let file = get_file(s)?;
    let int = parse_int(&file)?;
    Ok(int)
}

fn main() {
    let res = handle_file("some.txt");
    match res {
      Ok(res_code) => println!("res_code is {}", res_code),
      Err(IoError(err)) => println!("io_err is {}", err),
      Err(NumParseIntError(err)) => println!("parse_err is {}", err),
    };
}

```

or the following example:

```rust
fn handle_file(s: &str) -> u32 throws MyError { // Auto generated result Result<u32, MyError>
    let file = get_file(s)?;
    let int = parse_int(&file)?;
    Ok(int)
}

fn main() {
    let res = handle_file("some.txt");
    match res {
      Ok(res_code) => println!("res_code is {}", res_code),
      Err(IoError(err)) => println!("io_err is {}", err),
      Err(NumParseIntError(err)) => println!("parse_err is {}", err),
    };
}

```

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [April 24, 2020, 6:43pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/16 "2020-04-24T18:43:18Z")

</div>

Where do the names `Io` or `Parser` come from? That's the main issue.

---

<div class="post-metadata">

**Author:** ![redradist](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/redradist/32/6475_2.png) [@redradist](https://internals.rust-lang.org/u/redradist)\
**Post date:** [April 24, 2020, 6:46pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/17 "2020-04-24T18:46:13Z")

</div>

> [@CAD97](#):
>
> Where do the names `Io` or `Parser` come from? That's the main issue.

Please, take a look at the begining of post `io::Error` goes from `get_file` and `num::ParseIntError` goes from `parse_int` functions

Under cover Rust will generate enum `MyError` which will contain this errors:

```rust
enum MyError {
    // IoError generated field based on module and error type
    IoError(io::Error),
    // NumParseIntError generated field based on module and error type
    NumParseIntError(num::ParseIntError)
}

```

---

<div class="post-metadata">

**Author:** ![redradist](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/redradist/32/6475_2.png) [@redradist](https://internals.rust-lang.org/u/redradist)\
**Post date:** [April 24, 2020, 6:58pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/18 "2020-04-24T18:58:58Z")

</div>

> [@Aloso](#):
>
> An alternative would be anonymous enums that automatically coerce into their supersets:
> 
> ```rust
> fn handle_file(s: &str) -> Result<u32, io::Error | num::ParseIntError> {
> let content = std::fs::read_to_string(s)?;
> let int: u32 = content.parse()?;
> Ok(int)
> }
> 
> match handle_file("") {
> Ok(n) => n,
> Err(e @ io::Error) => todo!(),
> Err(e @ num::ParseIntError) => todo!(),
> }
> 
> ```
> 
> Anonymous enums have been [proposed before](https://users.rust-lang.org/t/anonymous-enums/5478).

I like this idea of anonymous enum !!

If we would have such syntax it would be possible to handle multiple errors without introducing a new keyword `throws` !!

---

<div class="post-metadata">

**Author:** ![pythoneer](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pythoneer/32/2010_2.png) [@pythoneer](https://internals.rust-lang.org/u/pythoneer)\
**Post date:** [April 24, 2020, 7:43pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/19 "2020-04-24T19:43:06Z")

</div>

> [@redradist](#):
>
> If we would have such syntax it would be possible to handle multiple errors without introducing a new keyword `throws` !!

We had people trying to come up with a coherent solution for over 4 years and at least with 3 serious efforts if i remember correcly. This problem is just not as easy as one might think at the beginning.

---

<div class="post-metadata">

**Author:** ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)\
**Post date:** [April 24, 2020, 8:50pm UTC](https://internals.rust-lang.org/t/simplify-error-handling/12226/20 "2020-04-24T20:50:00Z")

</div>

Depending on what you're looking for, you could also use `anyhow::Result<u32>`, which will wrap any error you like and not require creating any types. You can still get a specific error type out of it if you need to (using downcasting), and in the common case where all errors just get reported without being matched on, you don't need to do anything at all.

Might that give you the reduced boilerplate you're looking for?

[Next page](https://internals.rust-lang.org/t/simplify-error-handling/12226.md?page=2)
