Kind() method not found when using anyhow and thiserror

Hello,

Go easy on my because I am new on Rust so am probably doing something dumb here. I posted this on the anyhow repo and it was (probably rightly) promptly closed and I was instead advised to post it here. I searched this forum and no previous answer immediately popped out.

I'm trying to have a function return a custom error when it fails with a known issue. The function could also return other errors. I then want another function to be able to do a match on the custom returned error and, if it is the known error, do something else to attempt to recover. If some other error is encountered, I just want to bubble it up.

However, when I try to do this, I receive an error. The error is obvious enough but I cannot determine how to resolve it. Do I need to implement kind() for my custom error somehow? I've spent more time than I should trying to figure it out and decided it was time enough to "phone a friend". Thank you for your help in advance.

Here is a constructed simple as I can make it main.rs example that reproduces this issue. In my real solution, I would have the error definitions in their own module and the two my_* functions also in theirs. But, I put it all in one here for purposes of the question.

use anyhow::Result;
use thiserror::Error;

#[derive(Error, Debug)]
enum MyCustomError {
    #[error("This is a custom error")]
    MyError,
}

fn my_failable_fn() -> Result<String> {
    Err(MyCustomError::MyError)?
}

fn my_recovery_fn() -> Result<String> {
    Ok("Recovered".to_string())
}

fn test() -> Result<()> {
    let x = match my_failable_fn() {
        Ok(value) => value,
        Err(e) if e.kind() == MyCustomError::MyError => my_recovery_fn()?,
        Err(e) => return Err(e),
    };
    println!("{}", x);
    Ok(())
}

fn main() {
    test().unwrap();
}

My Cargo.toml is:

[package]
name = "anyhow-problem"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
anyhow = "1.0.65"
thiserror = "1.0.35"

And, the error I receive is:

error[E0599]: no method named `kind` found for struct `anyhow::Error` in the current scope
  --> src/main.rs:20:21
   |
20 |         Err(e) if e.kind() == MyCustomError::MyError => {
   |                     ^^^^ method not found in `anyhow::Error`

Where do you think the kind method is coming from? There are some error types in the standard library with a kind method, but anyhow doesn't use any methods named kind.

You probably want either one of the downcast methods, or possibly is.

Playground

use anyhow::Result;
use thiserror::Error;

#[derive(Error, Debug, PartialEq)]
enum MyCustomError {
    #[error("This is a custom error")]
    MyError,
}

fn my_failable_fn() -> Result<String> {
    Err(MyCustomError::MyError)?
}

fn my_recovery_fn() -> Result<String> {
    Ok("Recovered".to_string())
}

fn test() -> Result<()> {
    let x = match my_failable_fn() {
        Ok(value) => value,
        Err(e) if e.downcast_ref() == Some(&MyCustomError::MyError) => my_recovery_fn()?,
        Err(e) => return Err(e),
    };
    println!("{}", x);
    Ok(())
}

fn main() {
    test().unwrap();
}

You also were missing PartialEq in the derive for MyCustomError to allow comparing with ==

3 Likes

This is exactly the solution.

I had tried downcast_ref() and also is() but couldn't get it to work. Perhaps it was because of the PartialEq I also missed.

Thank you for your help!