`the trait `std::error::Error` is not implemented for `&str`

I am using derive_more to generate try_into implementation, and anyhow for returning my errors.

use derive_more::*;
use std::convert::TryInto;
use anyhow::*;

#[derive(Debug)]
struct A;

#[derive(Debug)]
struct B;

#[derive(Debug, TryInto)]
enum AB {
    A(A),
    B(B),
}

The following code compiles and run perfectly:

fn main() {
    let a: A = AB::A(A).try_into().unwrap(); // works
    println!("{:?}", a); 
    let b: B = AB::A(A).try_into().unwrap(); // will fail, as expected
    println!("{:?}", b); 
}

But as soon as I try to remove the unwrap, it start to be complicated.

fn main() -> Result<()> {
    let a: A = AB::A(A).try_into()?;
    println!("{:?}", a);
    let b: B = AB::A(A).try_into()?;
    println!("{:?}", b);
    Ok(())
}
let a: A = AB::A(A).try_into()?;
                              ^ the trait `std::error::Error` is not implemented for `&str`

Apparently &'static str doesn't implements std::error::Error for reasons that I don't understand. Is there any easier way to convert a std::result::Result<B, &'static str> into something compatible with anyhow? This works but it's ways too verbose, and hard to read:

fn main() -> Result<()> {
    let a: std::result::Result<A, &'static str> = AB::A(A).try_into();
    let a = match a {
        Err(err) => {
            bail!(err)
        },
        Ok(ok) => ok,
    };
    println!("{:?}", a);

    let b: std::result::Result<B, &'static str> = AB::A(A).try_into();
    let b = match b {
        Err(err) => {
            bail!(err)
        },
        Ok(ok) => ok,
    };
    println!("{:?}", b);

    Ok(())
}

It took me 20 minutes of research to write this post, and obviously I found the solution 2 mn after posting!

fn main() -> Result<()> {
    let a: A = AB::A(A).try_into().map_err(|err: &'static str| format_err!("{:?}", err))?;
    println!("{:?}", a);

    let b: B = AB::A(A).try_into().map_err(|err: &'static str| format_err!("{:?}", err))?;
    println!("{:?}", b);

    Ok(())
}

Edit: the 'static isn't even needed.

2 Likes

You can use anyhow::Error::msg, which is specifically crafted for this purpose:

let a: A = AB::A(A).try_into().map_err(Error::msg)?;

The .map_err(Error::msg) usage is directly mentioned in the documentation, so it's probably the most simple and idiomatic approach.

3 Likes

That's even better, thanks.

To be honest this definitely looks like an issue with derive_more's TryInto derive: instead of returning a &'static str on error, it should return a newtype that implements Error, at least when std is enabled.

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.