Is it possible to prepend an error using error-chain?

#1

I have a scenario like this:

fn process(job: i32, data: &Data) -> Result<()> { // pseudo-code
    work(&data)?;
    Ok(())
}

The work function knows nothing about the job number it is working on, but could fail with various errors (std::num::ParseIntError, std::io::Error, etc, all error_chain foreign_links).

I know that I can do this:

work(&data).chain_err(|| format!("Job {}", job))?;

But what I really want is to prefix the error with the job number.

Is this possible?

#2

You could use map_err to construct whatever error you want. Something like this (untested):

work(&data).map_err(|err| Err(JobFailed(job)).chain_err(|| err))?;

However I’m not sure why you would want that. The default error order that chain_err gives you is more correct: the cause of a job failure is that work() has failed, not the other way around.

#3

The reason I need to prepend is that each work() occurs in a thread (using rayon) so I want to construct error messages in the main thread of the form “Job number: error message”.

I tried your suggestion & many variations but couldn’t figure it out.

The closest I’ve got is this:

// inside error_chain!
    errors { Fail(u: u32, err: String) { display("[{: >5}] {}", u, err) } }
// elsewhere
pub fn get_error(err: Error) -> String {
    let mut error = format!("ERROR: {}", err);
    for err in err.iter().skip(1) {
        error.push_str(&format!(": {}", err));
    }
    error
}
// at the point of use:
let reply = work(&data)
    .map_err(|err| Err(ErrorKind::Fail(u, get_error(err))))?;

This fails to compile with:

error[E0277]: the trait bound `errors::Error: std::convert::From<std::result::Result<_, errors::ErrorKind>>` is not satisfied
  --> src/plan/process.rs:62:25
   |
62 |           let reply = work(&data)
   |  __________________^
63 | |             .map_err(|err| Err(ErrorKind::Fail(u, get_error(err))))?;
   | |____________________________________________________________________^ the trait `std::convert::From<std::result::Result<_, errors::ErrorKind>>` is not implemented for `errors::Error`