RS.CLIPPY.AWAIT_HOLDING_LOCK

Inside an async function, holding a `MutexGuard` while calling `await`

This checker is a Clippy lint created by The Rust Project Contributors. The documentation shown here is a copy of the original documentation for: await_holding_lock. Copyright ©2025 The Rust Team. All rights reserved.

What it does

Checks for calls to await while holding a non-async-aware MutexGuard.

Why is this bad?

The Mutex types found in std::sync and parking_lot are not designed to operate in an async context across await points.

There are two potential solutions. One is to use an async-aware Mutex type. Many asynchronous foundation crates provide such a Mutex type. The other solution is to ensure the mutex is unlocked before calling await, either by introducing a scope or an explicit call to Drop::drop.

Known problems

Will report false positive for explicitly dropped guards (#6446). A workaround for this is to wrap the .lock() call in a block instead of explicitly dropping the guard.

Example

async fn foo(x: &Mutex<u32>) {
  let mut guard = x.lock().unwrap();
  *guard += 1;
  baz().await;
}

async fn bar(x: &Mutex<u32>) {
  let mut guard = x.lock().unwrap();
  *guard += 1;
  drop(guard); // explicit drop
  baz().await;
}

Use instead:

async fn foo(x: &Mutex<u32>) {
  {
    let mut guard = x.lock().unwrap();
    *guard += 1;
  }
  baz().await;
}

async fn bar(x: &Mutex<u32>) {
  {
    let mut guard = x.lock().unwrap();
    *guard += 1;
  } // guard dropped here at end of scope
  baz().await;
}