rust-lang/rust · error
use of `await` outside of an async context.
Error message
use of `await` outside of an async context.
What it means
This `unreachable!` fires inside the `.await` desugaring helper when `self.task_context` is `None`, i.e. the lowering context has no enclosing async task context to pull a `task_context` binding from. By the time `.await` is being lowered, the parser/type-checker should already have emitted a clean user-facing error for `await` outside an async function/block/closure. Reaching this point means that gate was bypassed — an internal compiler bug.
Source
Thrown at compiler/rustc_ast_lowering/src/expr.rs:1032
// this name to identify what is being awaited by a suspended async functions.
let awaitee_ident = Ident::with_dummy_span(sym::__awaitee);
let (awaitee_pat, awaitee_pat_hid) =
self.pat_ident_binding_mode(gen_future_span, awaitee_ident, hir::BindingMode::MUT);
let task_context_ident = Ident::with_dummy_span(sym::_task_context);
// unsafe {
// ::std::future::Future::poll(
// ::std::pin::Pin::new_unchecked(&mut __awaitee),
// ::std::future::get_context(task_context),
// )
// }
let poll_expr = {
let awaitee = self.expr_ident(span, awaitee_ident, awaitee_pat_hid);
let ref_mut_awaitee = self.expr_mut_addr_of(span, awaitee);
let Some(task_context_hid) = self.task_context else {
unreachable!("use of `await` outside of an async context.");
};
let task_context = self.expr_ident_mut(span, task_context_ident, task_context_hid);
let new_unchecked = self.expr_call_lang_item_fn_mut(
span,
hir::LangItem::PinNewUnchecked,
arena_vec![self; ref_mut_awaitee],
);
let get_context = self.expr_call_lang_item_fn_mut(
gen_future_span,
hir::LangItem::GetContext,
arena_vec![self; task_context],
);
let call = match await_kind {
FutureKind::Future => self.expr_call_lang_item_fn(
span,
hir::LangItem::FuturePoll,View on GitHub (pinned to 22057b88b0)
Solutions
- As a user who sees the ICE: report it with the reproducer to https://github.com/rust-lang/rust/issues.
- Move the `.await` into an `async fn`/`async {}` block — if the earlier diagnostic fires instead, the bug is elsewhere.
- If a proc-macro is injecting await expressions, ensure they only land inside async contexts.
- If developing rustc: confirm the parser/sema check that rejects `.await` outside async (the `allow_await` feature-gate path) ran before lowering, and that `task_context` is set whenever the function enters an async scope.
Example fix
// before — .await outside async context (should be caught earlier, but bypassed)
fn run() -> u8 { fut.await }
// after — wrap in an async context
async fn run() -> u8 { fut.await } Defensive patterns
Strategy: validation
Validate before calling
// `.await` is only legal inside an async context. Validate the enclosing
// item is async BEFORE writing the await, or wrap the call in an async block.
//
// Good: async fn fetch() { req.await; }
// Bad: fn fetch() { req.await; } // ICE/error: await outside async
//
// Pre-commit guard (catch it at source, not at lowering):
// rg -n '\.await' --type rust | rg -v 'async (fn|move|\{)'
//
// If you must call async code from sync code, spawn an executor:
// let r = tokio::runtime::Runtime::new()?.block_on(async { req.await }); Prevention
- Only use `.await` inside `async fn`, `async {}`, or `async move {}`
- If a sync caller needs async results, bridge via a runtime's `block_on`
- Enable clippy::await_holding_lock / async-aware lints to surface context mistakes early
- Add a pre-commit grep for `.await` outside `async` items
When it happens
Trigger: Triggered when `lower_await` (the `.await` desugaring at expr.rs:1031) is invoked but `self.task_context` was never set — there is no enclosing `async fn`, `async {}`, `async ||`, or other coroutine context that establishes a task-context binding. The `let Some(task_context_hid) = self.task_context else { unreachable!(...) }` arm fires.
Common situations: In principle user-facing: writing `.await` in a non-async function should produce a graceful E0728-style diagnostic long before lowering. This `unreachable!` is the backstop for when the earlier check is missing (a rustc regression). It can also be hit by procedural-macro-injected `.await` nodes into sync contexts, or by nightly features (`gen` blocks, async-fn-in-traits edge cases) where the context-tracking logic has a hole.
Related errors
- non-`async`/`gen` closure body turned `async`/`gen` during l
- assignment does not match variant
- shouldn't exist here
- must contain self type as `SelfTy` propagation kind is speci
- arg must exist for infer
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/921d7d0cce73839e.json.
Report an issue: GitHub.