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

  1. As a user who sees the ICE: report it with the reproducer to https://github.com/rust-lang/rust/issues.
  2. Move the `.await` into an `async fn`/`async {}` block — if the earlier diagnostic fires instead, the bug is elsewhere.
  3. If a proc-macro is injecting await expressions, ensure they only land inside async contexts.
  4. 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

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


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/921d7d0cce73839e.json. Report an issue: GitHub.