{"record":{"id":"aa4346accf8d2f0a","repo":"transact-rs/sqlx","slug":"cleanup-test-invoked-outside-sqlx-test","errorCode":null,"errorMessage":"cleanup_test() invoked outside `#[sqlx::test]`","messagePattern":"cleanup_test\\(\\) invoked outside `#\\[sqlx::test\\]`","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sqlx-mysql/src/testing/mod.rs","lineNumber":32,"sourceCode":"use sqlx_core::query_scalar::query_scalar;\nuse sqlx_core::sql_str::AssertSqlSafe;\n\npub(crate) use sqlx_core::testing::*;\n\n// Using a blocking `OnceLock` here because the critical sections are short.\nstatic MASTER_POOL: OnceLock<Pool<MySql>> = OnceLock::new();\n\nimpl TestSupport for MySql {\n    fn test_context(\n        args: &TestArgs,\n    ) -> impl Future<Output = Result<TestContext<Self>, Error>> + Send + '_ {\n        test_context(args)\n    }\n\n    async fn cleanup_test(db_name: &str) -> Result<(), Error> {\n        let mut conn = MASTER_POOL\n            .get()\n            .expect(\"cleanup_test() invoked outside `#[sqlx::test]`\")\n            .acquire()\n            .await?;\n\n        do_cleanup(&mut conn, db_name).await\n    }\n\n    async fn cleanup_test_dbs() -> Result<Option<usize>, Error> {\n        let url = dotenvy::var(\"DATABASE_URL\").expect(\"DATABASE_URL must be set\");\n\n        let mut conn = MySqlConnection::connect(&url).await?;\n\n        let delete_db_names: Vec<String> = query_scalar(\"select db_name from _sqlx_test_databases\")\n            .fetch_all(&mut conn)\n            .await?;\n\n        if delete_db_names.is_empty() {\n            return Ok(None);\n        }","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/transact-rs/sqlx/blob/03af8bcc5711a1935580a54bea249c219a0c217d/sqlx-mysql/src/testing/mod.rs#L14-L50","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","solutions":["Annotate the test with `#[sqlx::test]` so MASTER_POOL is initialized; drop manual cleanup calls.","Remove direct `cleanup_test` calls — the macro performs cleanup automatically.","If you need manual DB cleanup, connect with your own pool via DATABASE_URL instead of the testing API."],"exampleFix":"// before\n#[tokio::test]\nasync fn t() { cleanup_test(\"mydb\").await.unwrap(); }\n// after\n#[sqlx::test]\nasync fn t(pool: MySqlPool) { /* cleanup is automatic */ }","handlingStrategy":"validation","validationCode":"// Only call cleanup inside a #[sqlx::test]; assert initialization first:\n// (testing API is internal — guard by convention)\nfn ensure_sqlx_test_context() {\n    // cleanup_test requires MASTER_POOL set by #[sqlx::test]\n    panic!(\"do not call cleanup_test outside #[sqlx::test]\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use #[sqlx::test] for every test that needs a DB and let it clean up automatically","Never call testing-module cleanup helpers from #[tokio::test] or application code","Search the codebase for direct cleanup_test invocations during refactors"],"tags":["sqlx","mysql","testing","panic","misuse"],"backgroundTag":"test-context-misuse","analyzedSha":"03af8bcc5711a1935580a54bea249c219a0c217d","analyzedAt":"2026-09-03T15:01:28.752Z","contentChangedAt":"2026-09-03T15:01:28.752Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}