Thiserror: Multiple "froms"/sources?

I am still at the very beginning of my Rust journey and currently in the process of removing all my temporary unwrap()s from my code and I stumbled across thiserror which seems useful.

I have one question though:

  • I have a function calling other things that returns three or more different Error types

  • I'd like to return a custom error instead that's either a DatabaseError or a ValidationError

  • Two or more source errors map to a single custom error (e.g. two different errors map to DatabaseError)

  • I'd like to keep the original errors for context / error messages etc.

Using thiserror I'm not sure how to achieve this

#[derive(Error, Debug)]
pub enum Error {
    #[error("DB error")]
    DatabaseError {
        #[from]
        source: <??? What goes here ???>
    }

    #[error("Validation error")]
    ValidationError(String)
}

I played around with source: Box<dyn std::error::Error + Send + 'static> but didn't get anywhere with errors like this:

   |                                          ^ the trait `std::convert::From<r2d2::Error>` is not implemented for `storage::StorageError`
   |
   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
   = help: the following implementations were found:
             <storage::StorageError as std::convert::From<std::boxed::Box<(dyn std::error::Error + std::marker::Send + 'static)>>>
   = note: required by `std::convert::From::from`

I'm looking for any hints on how to solve this.
I believe I might be able to write an Error manually that does what I want but considering that I can't get it to run using thiserror I'm afraid I'm doing something wrong/unidiomatic.

AFAIK, in this case DatabaseError is usually a nested enum, not a simple variant.

Thanks. I didn't actually think of that.

That said I'm not sure I like that solution a lot because those nested variants will be visible to users but are really an implementation detail that I don't want exposed.

I think it’s reasonable and idiomatic to write manual impls in this case.

Thank you, that's what I ended up doing.