Convert Box<dyn Error> to Box<dyn Error + Send>

Hi everyone.
I have an async method that can return a result containing an error. But since the method is used inside tokio threads, the error type that it returns should impl Send trait, Like this:

async fn connect() -> Result<TcpStream, Box<dyn Error + Send>> { ... }

But the problem is, after adding Send to trait bounds, I can't return normal errors using question mark ? anymore, and this for example leads to trait bound error:

Err("No proxies provided.")?;

Is there any solution?

Thanks

Add + Sync

2 Likes

Thanks!
Could you please explain why is this required?

Error conversion using ? is not a hardcoded magic, but invokes From::from(). You can search "dyn Error" on the implementors list of From. We have ones for Box<dyn Error> and Box<dyn Error + Send + Sync>, but not Box<dyn Error + Send>.

1 Like

I have another problem now.

async fn connect() -> Result<TcpStream, Box<dyn Error + Send + Sync>> {
    do_some().await?;
}

async fn do_some() -> Result<(), Box<dyn Error>> {
    Ok(())
}

I can't use ? for normal Result<(), Box<dyn Error>>anymore. Also I can't edit functions like do_some() since they are imported from other crates.
It results in following errors.

error[E0277]: the size for values of type `dyn std::error::Error` cannot be known at compilation time
  --> src/main.rs:32:24
   |
32 |         do_some().await?;
   |                        ^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `dyn std::error::Error`
   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
   = note: required because of the requirements on the impl of `std::error::Error` for `std::boxed::Box<dyn std::error::Error>`
   = note: required because of the requirements on the impl of `std::convert::From<std::boxed::Box<dyn std::error::Error>>` for `std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>`
   = note: required by `std::convert::From::from`

error[E0277]: `dyn std::error::Error` cannot be sent between threads safely
  --> src/main.rs:32:24
   |
32 |         do_some().await?;
   |                        ^ `dyn std::error::Error` cannot be sent between threads safely
   |
   = help: the trait `std::marker::Send` is not implemented for `dyn std::error::Error`
   = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<dyn std::error::Error>`
   = note: required because it appears within the type `std::boxed::Box<dyn std::error::Error>`
   = note: required because of the requirements on the impl of `std::convert::From<std::boxed::Box<dyn std::error::Error>>` for `std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>`
   = note: required by `std::convert::From::from`

error[E0277]: `dyn std::error::Error` cannot be shared between threads safely
  --> src/main.rs:32:24
   |
32 |         do_some().await?;
   |                        ^ `dyn std::error::Error` cannot be shared between threads safely
   |
   = help: the trait `std::marker::Sync` is not implemented for `dyn std::error::Error`
   = note: required because of the requirements on the impl of `std::marker::Sync` for `std::ptr::Unique<dyn std::error::Error>`
   = note: required because it appears within the type `std::boxed::Box<dyn std::error::Error>`
   = note: required because of the requirements on the impl of `std::convert::From<std::boxed::Box<dyn std::error::Error>>` for `std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>`
   = note: required by `std::convert::From::from`

It's impossible to convert a Box<dyn Error> to Box<dyn Error + Send + Sync> because a Box<dyn Error> is neither Send nor Sync.

I guess you could turn the error into a string and convert that to the right error.

Could you please provide an example?

You can convert it to a string with err.to_string().

I wrote this, but I'm not actually sure if it's a good way.

do_some().await.fix_box()?
trait FixBoxError<T> {
    fn fix_box(self) -> Result<T, Box<dyn Error + Send + Sync>>;
}
impl<T> FixBoxError<T> for Result<T, Box<dyn Error>> {
    fn fix_box(self) -> Result<T, Box<dyn Error + Send + Sync>> {
        match self {
            Err(err) => Err(err.to_string().into()),
            Ok(t) => Ok(t),
        }
    }
}

The good way would be to fix the thing returning a Box<dyn Error>, but if that's not possible, I guess it's ok.

Well I think that's impossible, since the method is async and it is used between threads.