Propagating a mapped error fails

I have some difficulties right now to propagate a custom error with the ? operator up to a higher caller.

My lib-specific result type is defined like so:

pub type AlsError = Box<dyn std::error::Error + Send + Sync>;
pub type AlsResult<T> = Result<T, AlsError>;

The following code produces the compilation error:

// Some type for a network communication protocol
pub struct ComHeader {
     ...
     transaction_no: u32,
     ...
}

// Parsing some specific bytes received from a `TcpStream` to an instance of `ComHeader`
impl TryFrom<&[u8]> for ComHeader {
  type Error = AlsError;
  fn try_from(buffer: &[u8]) -> AlsResult<Self> {
     ...
     let transaction_no = u32::from_be_bytes(
      buffer[up_to_trans_no..up_to_trans_name]
        .try_into()
        // I want to propagate a custom error here, as the original one lacks some crucial information
        .map_err(|_| {
          Err(throw!(
            2,
            AlsErrorKind::TypeParse,
            format!(
              "Parse for variable 'transaction_no' failed for value `{:?}`",
              buffer[up_to_trans_no..up_to_trans_name].to_vec()
            )
          ))
        })?, // Row 166
    );
     ...
     Ok(ComHeader {
         ...
         transaction_no,
         ...
     })
  }
}

But the compiler complains while building the library:

error[E0277]: the trait bound `Result<_, Box<dyn std::error::Error + Send + Sync>>: std::error::Error` is not satisfied
   --> src/net/base/com_header.rs:166:11
    |
166 |         })?,
    |           ^ the trait `std::error::Error` is not implemented for `Result<_, Box<dyn std::error::Error + Send + Sync>>`
    |
    = note: required because of the requirements on the impl of `From<Result<_, Box<dyn std::error::Error + Send + Sync>>>` for `Box<dyn std::error::Error + Send + Sync>`
    = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, Result<_, Box<dyn std::error::Error + Send + Sync>>>>` for `Result<com_header::ComHeader, Box<dyn std::error::Error + Send + Sync>>`

What I don't understand here is that:

  1. The error returned by the throw! macro implements std::error::Error, so why is this trait bound not satisfied?
  2. Why does Rust check if the type Result<_, Box<dyn std::error::Error + Send + Sync>> implements Error, when instead Rust should check the Result's Err variant instead?

Thanks in advance!

Try removing the Err( ) around throw!( ) :wink:

Note the signature

pub fn map_err<F, O>(self, op: O) -> Result<T, F>
where
    O: FnOnce(E) -> F, 

the thing returned by the closure is expected to be just the error (of type F), not a new Result.

The constructor Err on the other hand does create a Result, its signature is basically fn Err<T, E>(e: E) -> Result<T, E>.

2 Likes

Aww man, I guess things like that happen when you should have called it a day a few hours earlier :sweat_smile:
Thanks buddy!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.