79184774

Date: 2024-11-13 12:00:52
Score: 0.5
Natty:
Report link

In this case, the compiler is your friend. The answer is in the error message:

note: upstream crates may add a new impl of trait `std::error::Error` for type `anyhow::Error` in future versions

The problem is, you have these two impl blocks:

impl<E> From<E> for MyError
where
    E: std::error::Error + Into<anyhow::Error>,
{
    fn from(e: E) -> Self {
        MyError::Anyhow(e.into())
    }
}

impl From<anyhow::Error> for MyError {
    fn from(e: anyhow::Error) -> Self {
        MyError::Anyhow(e)
    }
}

Now consider what happens when you try to convert anyhow::Error into MyError. The compiler sees the first block and tries to match: anyhow::Error implements Into<anyhow::Error> (any type T trivially implements Into<T>), but doesn't implement std::error::Error, so we should be fine here (spoiler alert: we aren't, but we'll get back to this later). It also sees the second block, where we have From<anyhow::Error>, so it obviously applies and the compiler can use it.

However, you don't have any guarantee that the anyhow crate maintainers won't introduce an implementation for std::error::Error for anyhow::Error in the future. This sort of change only needs a minor SemVer bump, so your code could suddenly stop compiling without even changing your Cargo.toml. Rust compiler tries to prevent this and doesn't allow you to build your program, even though there's technically nothing wrong with it as of today.

What can you do with it? Well, sadly not that much. Your options are:

  1. Removing generic From<E> implementation and implementing From for all the error types you want to support (possibly using macros) — your code stops being generic
  2. Removing the std::error::Error bound on From<E> and removing From<anyhow::Error> block — requires you to remove your impl From<MyError> for anyhow::Error block because of conflicting blanket implementation of impl<T> From<T> for T
  3. Removing the Into<anyhow::Error> bound on From<E> and using std::error::Error + Send + Sync + 'static instead while removing the From<anyhow::Error> — you won't be able to convert from anyhow::Error to MyError.

There is a possibility this problem will be easier to tackle in the future using specialization, but it doesn't look like it will be available in stable Rust anytime soon.


See also: How do I work around the "upstream crates may add a new impl of trait" error?

Reasons:
  • Blacklisted phrase (1): How do I
  • Long answer (-1):
  • Has code block (-0.5):
  • Ends in question mark (2):
  • High reputation (-1):
Posted by: m4tx