Search code examples
rustreqwest

`?` couldn't convert the error to `std::io::Error`


I am attempting to do a post using the reqwest library and following patters that I have found in various places online:

let res = http_client.post(&url)
                          .header("Content-Type", "application/x-www-form-urlencoded")
                          .form(&form_data)
                          .send()
                          .await?;
println!("authenticate response: {}", res.status)

The code block above causes a compile error:

`?` couldn't convert the error to `std::io::Error` the trait ` 
      `std::convert::From<reqwest::error::Error>` is not implemented for `std::io::Error`

I do not understand why I am getting this error. I have made my code as close to the examples as I can. It will compile if I remove the ? and the res.status. But I need to get the status res.status value. More importantly, I need to understand what I am missing or doing wrong.


Solution

  • Your error is caused by the return type of the function from where you call this block, the compiler wants to return a error of the type std::io::Error.

    From the error description, I draw the conclusion your main function looks something like this:

    fn main() -> Result<(), std::io::Error> {
        // ...
    }
    

    The problem is that reqwest does not return an io::Error. This is a snippet I wrote a few months ago:

    use exitfailure::ExitFailure;
    
    fn main() -> Result<(), ExitFailure> {
        let res = http_client
            .post(&url)
            .header("Content-Type", "application/x-www-form-urlencoded")
            .form(&form_data)
            .send()
            .await?;
    
        println!("authenticate response: {}", res.status);
        Ok(())
    }
    

    I used exitfailure to convert the returned error type to a human-readable return type for main. I think it will solve your issue too.

    Update: It was pointed out in the comments, exifailure have deprecated dependencies and this could be achieved without an external crate. There is a recommended way of returning an encapsulated dynamic error: Box<dyn std::error::Error>

    fn main() -> Result<(), Box<dyn std::error::Error>> {
        let res = http_client
            .post(&url)
            .header("Content-Type", "application/x-www-form-urlencoded")
            .form(&form_data)
            .send()
            .await?;
    
        println!("authenticate response: {}", res.status);
        Ok(())
    
    }
    

    From what I could see the behavior in returning agreageted errors from main is identical.