'Mixing anyhow::Result with std::io::Result

Can anyone help me understand why this code compiles fine:

use actix_web::{App, HttpServer};
use anyhow::Result;

mod error;

#[actix_rt::main]
async fn main() -> Result<()> {
    HttpServer::new(|| App::new())
        .bind("127.0.0.1:8080")?
        .run()
        .await?;

    Ok(())
}

while this does't compile:

use actix_web::{App, HttpServer};
use anyhow::Result;

mod error;

#[actix_rt::main]
async fn main() -> Result<()> {
    HttpServer::new(|| App::new())
        .bind("127.0.0.1:8080")?
        .run()
        .await
}

with the error:

error[E0308]: mismatched types
 --> src/main.rs:6:1
  |
6 | #[actix_rt::main]
  | ^^^^^^^^^^^^^^^^^ expected struct `anyhow::Error`, found struct `std::io::Error`
7 | async fn main() -> Result<()> {
  |                    ---------- expected `std::result::Result<(), anyhow::Error>` because of return type
  |
  = note: expected enum `std::result::Result<_, anyhow::Error>`
             found enum `std::result::Result<_, std::io::Error>`
  = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

What is fundamentally different between the two examples?



Solution 1:[1]

The problem is that the second example is returning Result<(), std::io::Error> which is returned by starting the server, whereas the second one is returning Result<(), anyhow::Error> in the form of Ok(()).

The reason the first example works is that the ? operator (or the try! macro) performs a conversion from whatever error is returned to the error of the return type of the function.

From the docs:

In case of the Err variant, it retrieves the inner error. try! then performs conversion using From. This provides automatic conversion between specialized errors and more general ones.

Solution 2:[2]

anyhow::Error implements From<std::error::Error>, but they are not the same thing.

In the first one the ? is taking the std::error::Error from run().await and calling anyhow::Error::from. The second one is not.

Changing the return type of your method to

Result<(), std::error::Error>

fixes the issue.

Solution 3:[3]

You can use the same conversion that anyhow uses:

use actix_web::{App, HttpServer};
use anyhow::Result;

mod error;

#[actix_rt::main]
async fn main() -> Result<()> {
    HttpServer::new(|| App::new())
        .bind("127.0.0.1:8080")?
        .run()
        .await.map_err(anyhow::Error::from)
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Bennett Hardwick
Solution 2 pigeonhands
Solution 3 Caleb Hattingh