Shouldn't `Box<T> where T: Error` implement `Error` regardless whether `T: Sized`?

I am dealing with the tracing crate, which at some point gives me an Box<dyn Error> and I noticed this type does not implement Error.

I found that the way the standard library is written, Box<T> where T: Error only implements Error when T: Sized. Is this an oversight or is this intentional? How do I change the Box<dyn Error> into an error regardless, that I can return using the anyhow crate?

In the standard library, this is the relevant code (link):

impl<T: Error> Error for Box<T> {

Shouldn't the trait be implemented as follows?

impl<T: Error + ?Sized> Error for Box<T> {

This would cause a conflict between the following two generic implementations that are already in the standard library:

impl<E: Error> From<E> for Box<dyn Error>

impl<T> From<T> for T

If Box<dyn Error> implemented Error then it would implement From<Box<dyn Error>> twice, because both of these impls would apply.

There's an issue open about this: https://github.com/rust-lang/rust/issues/60759

It sounds like the plan is to fix this eventually, once specialization is stable enough to support it.

2 Likes

@mbrubeck Is there a workaround for this since I would like to return an Error? Perhaps file an issue at tracing to have them add a Sized specifier on their return type?

dyn Error is a fundamentally unsized type, so they would have to change to some completely different error type.

This could be reasonable feature request. Using Box<dyn Error> in a library can be bad for interop, specifically because of this missing Error impl. However, it's a breaking change, so it would need a major version bump in the tracing-subscriber crate.

For now, it looks like the anyhow! macro can convert from Box<dyn Error> to anyhow::Error:

1 Like