thiserror: Generic type parameter on error

I ran into an error when having a generic parameter in my error type. So the setup is that I want to have a variant in my error enum such that it delegates to a different error, like below:

use thiserror::Error;

#[derive(Debug, Clone, Error)]
enum Error<E> {
    #[error("variant error")]
    Variant,
    #[error(transparent)]
    Delegate(#[from] E),
}

Unfortunately, I get an error about E not having a Debug instance:

error[E0277]: `E` doesn't implement `std::fmt::Debug`
 --> src/main.rs:4:1
  |
4 | enum Error<E> {
  | ^^^^^^^^^^ - help: consider restricting this bound: `E: std::fmt::Debug`
  | |
  | `E` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
  |
  = help: the trait `std::fmt::Debug` is not implemented for `E`
  = note: required because of the requirements on the impl of `std::fmt::Debug` for `Error<E>`

Could this be possible to do or is there something that is restricting this use case? 🤔

For now, I’m going to write out the implementations by hand, but it would be cool to delegate that work to thiserror.

Thanks for any help 🙏

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 15 (5 by maintainers)

Most upvoted comments

I may consider accepting an attribute to place an additional bound on just the generated std::error::Error impl.

#[derive(Error, Debug)]
#[error(bound = std::error::Error + 'static)]
enum Error<E> {
    #[error(transparent)]
    Delegate(#[from] E),
}

The example described in https://github.com/dtolnay/thiserror/issues/79#issuecomment-619122344 does not work with multiple #[from].

For example:

#[derive(Debug, thiserror::Error)]
pub enum MyError<E: std::error::Error + 'static> {
    #[error("io: {0}")]
    Io(#[from] std::io::Error),
    #[error(transparent)]
    Inner(#[from] E),
}

returns the following error:

conflicting implementations of trait `std::convert::From<std::io::Error>` for type `MyError<std::io::Error>`

is this because E could also be a std::io::Error?

Ya, I didn’t want to do that because then I have to litter the same bound everywhere I introduce E 😄

I was hoping that the generated code localise that like here:

impl<E: error::Error> error::Error for Error<E>