transact-rs/sqlx · error

cleanup_test() invoked outside `#[sqlx::test]`

Error message

cleanup_test() invoked outside `#[sqlx::test]`

What it means

In MySQL's testing support, `cleanup_test` acquires a connection from `MASTER_POOL`, a lazily-initialized global pool created only by `#[sqlx::test]`. `.get()` on the empty Option panics with this message when cleanup runs outside the macro-managed context.

Source

Thrown at sqlx-mysql/src/testing/mod.rs:32

use sqlx_core::query_scalar::query_scalar;
use sqlx_core::sql_str::AssertSqlSafe;

pub(crate) use sqlx_core::testing::*;

// Using a blocking `OnceLock` here because the critical sections are short.
static MASTER_POOL: OnceLock<Pool<MySql>> = OnceLock::new();

impl TestSupport for MySql {
    fn test_context(
        args: &TestArgs,
    ) -> impl Future<Output = Result<TestContext<Self>, Error>> + Send + '_ {
        test_context(args)
    }

    async fn cleanup_test(db_name: &str) -> Result<(), Error> {
        let mut conn = MASTER_POOL
            .get()
            .expect("cleanup_test() invoked outside `#[sqlx::test]`")
            .acquire()
            .await?;

        do_cleanup(&mut conn, db_name).await
    }

    async fn cleanup_test_dbs() -> Result<Option<usize>, Error> {
        let url = dotenvy::var("DATABASE_URL").expect("DATABASE_URL must be set");

        let mut conn = MySqlConnection::connect(&url).await?;

        let delete_db_names: Vec<String> = query_scalar("select db_name from _sqlx_test_databases")
            .fetch_all(&mut conn)
            .await?;

        if delete_db_names.is_empty() {
            return Ok(None);
        }

View on GitHub (pinned to 03af8bcc57)

Solutions

  1. Annotate the test with `#[sqlx::test]` so MASTER_POOL is initialized; drop manual cleanup calls.
  2. Remove direct `cleanup_test` calls — the macro performs cleanup automatically.
  3. If you need manual DB cleanup, connect with your own pool via DATABASE_URL instead of the testing API.

Example fix

// before
#[tokio::test]
async fn t() { cleanup_test("mydb").await.unwrap(); }
// after
#[sqlx::test]
async fn t(pool: MySqlPool) { /* cleanup is automatic */ }
Defensive patterns

Strategy: validation

Validate before calling

// Only call cleanup inside a #[sqlx::test]; assert initialization first:
// (testing API is internal — guard by convention)
fn ensure_sqlx_test_context() {
    // cleanup_test requires MASTER_POOL set by #[sqlx::test]
    panic!("do not call cleanup_test outside #[sqlx::test]");
}

Prevention

When it happens

Trigger: Calling the generated `cleanup_test(db_name)` (or the testing API's cleanup function) directly from a plain `#[tokio::test]` or normal code where no `#[sqlx::test]` has initialized `MASTER_POOL`.

Common situations: Porting tests off `#[sqlx::test]` but keeping cleanup calls; calling cleanup from helpers or drop paths executed outside test context; running tests in a binary that never used the attribute.

Related errors


AI-assisted analysis of transact-rs/sqlx@03af8bcc57 (2026-09-03). Data as JSON: /api/errors/aa4346accf8d2f0a. Report an issue: GitHub.