Output type mismatch misleadingly talks about mismatched async closure types
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
Code
use futures::{Stream, StreamExt, TryStreamExt};
async fn async_example(iter: impl Stream) {
iter.then(async |x| Ok(x))
.try_for_each_concurrent(8, async |_| { Ok(String::new()) })
}
Current output
error[E0308]: mismatched types
--> src/lib.rs:5:47
|
5 | .try_for_each_concurrent(8, async |_| { Ok(String::new()) })
| ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `String`
|
= note: expected `async` closure body `{async closure body@src/lib.rs:5:47: 5:68}` (`()`)
found `async` closure body `{async closure body@src/lib.rs:5:47: 5:68}` (`String`)
= note: no two async blocks, even if identical, have the same type
= help: consider pinning your async block and casting it to a trait object
error[E0308]: mismatched types
--> src/lib.rs:4:5
|
4 | / iter.then(async |x| Ok(x))
5 | | .try_for_each_concurrent(8, async |_| { Ok(String::new()) })
| | ^- help: consider using a semicolon here: `;`
| |____________________________________________________________________|
| expected `()`, found `TryForEachConcurrent<..., ..., ...>`
|
= note: expected unit type `()`
found struct `TryForEachConcurrent<Then<impl Stream, ..., ...>, ..., ...>`
= note: the full name for the type has been written to '/playground/target/debug/deps/playground-8c6566b9d438c411.long-type-6263624529938574077.txt'
= note: consider using `--verbose` to print the full type name to the console
Desired output
error[E0308]: mismatched types
--> src/lib.rs:5:47
|
5 | .try_for_each_concurrent(8, async |_| { Ok(String::new()) })
| -- ^^^^^^^^^^^^^ expected `()`, found `String`
| |
| arguments to this enum variant are incorrect
|
--> src/lib.rs:5:47
|
5 | .try_for_each_concurrent(8, async |_| { Ok(String::new()) })
| ^^^-------------^
| |
| this argument influences the type of `Ok`
note: tuple variant defined here
--> /playground/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs:561:5
|
561 | Ok(T),
| ^^
Rationale and extra context
The closures/futures do not need to be the same type, and attempting the dyn route will lead the user on a wild goose chase. The real error is what is being returned from the closure bodies.
In the less minimal example I'm including below, only the the first error is shown, so there is one relevant line out of 15.
The analogous code with Iterator and normal closures (instead of Stream and Future-returning errors) did not exhibit a misleading error in my (quick and unthorough) attempt: Playground.
Other cases
use anyhow::Error;
use futures::{self, Stream, StreamExt, TryStreamExt};
use futures::stream;
use std::pin::Pin;
type BoxStream<T> = Pin<Box<dyn Stream<Item = T>>>;
async fn inner_stream(_: u32) -> Result<BoxStream<Result<Vec<()>, Error>>, Error> {
todo!()
}
pub async fn outer_stream(iter: impl Iterator<Item = String> + Send) -> Result<(), Error> {
stream::iter(iter)
.then(async |x| Ok::<_, Error>(x))
.map_ok(async |_x| {
stream::iter([].into_iter())
.then(async |y| inner_stream(y).await)
.try_flatten()
.try_collect::<Vec<_>>()
})
.try_for_each_concurrent(8, async |x| {
x.await
})
.await?;
Ok(())
}
/*
error[E0308]: mismatched types
--> src/lib.rs:20:47
|
16 | .then(async |y| inner_stream(y).await)
| --------------------- the found `async` closure body
...
20 | .try_for_each_concurrent(8, async |x| {
| _______________________________________________^
21 | | x.await
22 | | })
| |_________^ expected `Result<(), anyhow::Error>`, found `TryCollect<TryFlatten<...>, ...>`
|
= note: expected `async` closure body `{async closure body@src/lib.rs:20:47: 22:10}` (`Result<(), anyhow::Error>`)
found `async` closure body `{async closure body@src/lib.rs:20:47: 22:10}` (`TryCollect<TryFlatten<...>, ...>`)
= note: no two async blocks, even if identical, have the same type
= help: consider pinning your async block and casting it to a trait object
For more information about this error, try `rustc --explain E0308`.
*/
Rust Version
Rust Playground
Stable channel Build using the Stable version: 1.98.0
Beta channel Build using the Beta version: 1.99.0-beta.1 (2026-08-17 f47d5bb13648d5c859f5)
Nightly channel Build using the Nightly version: 1.100.0-nightly (2026-08-22 c54751567b19c4ceb08b)
Anything else?
Inspired by this URLO thread.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the minimal Rust Playground example and comparing the current and desired E0308 diagnostics. Trace the compiler diagnostic path for async closure return-type mismatches and add a regression test covering the reported case; done means the output points to the Result::Ok argument without the misleading async-closure type explanation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100