Hey all! I’m encountering a confusing lifetime issue in a project using diesel_async, a custom pagination trait, and async-graphql.
The error doesn’t occur when I write the query inline, but does occur when I move the query into a build_query() function, even though I try to give it a 'static lifetime.
My custom pagination trait comes from this article: https://rymc.io/blog/2024/pagination-in-diesel-async/
What works (inline)
let (items, total) = users::table
.left_join(...)
.select(...)
.paginate(page)
.per_page(per_page)
.load_and_count_pages::<MyModel>(&mut conn)
.await?;
This works and compiles fine.
What fails (via function)
fn build_query(...) -> IntoBoxed<'static, _, Pg> {
users::table
.left_join(...)
.into_boxed()
}
let query = build_query(...);
let (items, total) = query
.paginate(page)
.per_page(per_page)
.load_and_count_pages::<MyModel>(&mut conn)
.await?;
This causes a lifetime error, but the error doesn’t appear at the call site — instead, it surfaces at the #[Object] macro from async-graphql:
error[E0477]: the type `Paginated<BoxedSelectStatement<'_, ...>>` does not fulfill the required lifetime
--> src/http/handlers/my_handler.rs:23:1
|
23 | #[Object]
| ^^^^^^^^^
What I’ve tried
- Made all input arguments owned (no references)
- Explicitly set the return type of
build_query()toBoxedSelectStatement<'static, _, _, Pg, _>
What I’d love help with
- Why does returning a boxed query from a function break
.paginate().awaitin a#[Object]resolver? - How can I structure the query builder so I can paginate it asynchronously inside
#[Object]? - Are there any best practices to avoid these lifetime traps when using Diesel + async + GraphQL?
Context
Rust version:
rustc 1.85.1 (4eb161250 2025-03-15)
Dependencies:
axum = { version = "0.8.1", features = ["multipart"] }
deadpool-diesel = { version = "0.6.1", features = ["postgres", "tracing"] }
diesel = { version = "2.2.8", features = ["chrono", "postgres", "serde_json"] }
diesel-async = { version = "0.5.2", features = ["deadpool", "postgres"] }
...
Any suggestions — even hacky workarounds — would be greatly appreciated! ![]()
Sorry if this is a noob question — I’m still new to Rust and still wrapping my head around lifetimes ![]()
I truly appreciate any pointers or explanations, even if they seem basic!