Lifetime error with tower::Service trait

I am facing two errors in the following code

#![deny(elided_lifetimes_in_paths)]

use reqwest::{Client, Method, Request, Url};
use std::error::Error;
use tower::{BoxError, Service, ServiceBuilder, ServiceExt};

struct Crawler {
    start_url: Url,
}

impl Crawler {
    fn service(&self) -> impl Service<Request, Error: Error + Send + Sync>{
        ServiceBuilder::new()
            // this triggers error #1
            .buffer(10)
            .concurrency_limit(10)
            .service(Client::new())
    }

    async fn start(&self) -> Result<(), BoxError> {
        let mut service = self.service();

        let client = service.ready().await?;

        let req = Request::new(Method::GET, self.start_url.clone());
        // this triggers error #2
        client.call(req).await?;
        Ok(())
    }
}
error[E0277]: the size for values of type `(dyn std::error::Error + Send + Sync + 'static)` cannot be known at compilation time
  --> src/lib.rs:12:26
   |
12 |     fn service(&self) -> impl Service<Request, Error: Error + Send + Sync> {
   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `(dyn std::error::Error + Send + Sync + 'static)`
   = help: the trait `std::error::Error` is implemented for `Box<E>`
   = note: required for `Box<(dyn std::error::Error + Send + Sync + 'static)>` to implement `std::error::Error`

error: lifetime may not live long enough
  --> src/lib.rs:22:22
   |
19 |     async fn start(&self) -> Result<(), BoxError> {
   |                    - let's call the lifetime of this reference `'1`
...
22 |         let client = service.ready().await?;
   |                      ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`

Playground

  1. I don't understand how error #1 is triggered, I can only guess it has something to do with the trait bounds here. I do know the following get rid of the error and I don't know what makes it work.
fn service(&self) -> impl Service<Request, Error: Error + Send + Sync> + use <>
  1. I don't know how error #2 is trigger too. I can only guess it has something to do with the Error type related to the Service trait but it is too cryptic for me.
1 Like

This doesn't look like a valid syntax. I'm surprised it doesn't fail to parse earlier.

If it gets interpreted as a trait, you end up returning unsized dyn Error that is an abstract concept that can't exist in a running program, instead of a concrete type like Box<dyn Error>.

The other lifetime error may be just a leftover from the compiler being confused and trying to check validity of a broken type that can't be returned.

it is a valid syntax and compiles by commenting out .buffer(10) and adding use<>

2 Likes

I think it's because without the use<>, the error is allowed to borrow *self and couldn't be coerced to a dyn 'static. I believe this is the case as the below suggestion also fixes the first error.

Due to coherence limitations, Box<dyn Error> doesn't implement Error. You can just specify the concrete type instead.

    fn service(&self) -> impl Service<Request, Error = BoxError> {

You may still want + use<> to avoid keeping the borrow of *self alive, if you know you never need that.

1 Like

It's introduced in 1.79.0.

1 Like