{"record":{"id":"9a13fa5b252b47c0","repo":"loco-rs/loco","slug":"drop-database","errorCode":null,"errorMessage":"Drop database","messagePattern":"Drop database","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/testing/db.rs","lineNumber":152,"sourceCode":"\n        // Run the drop on a dedicated OS thread with its own runtime (not\n        // `tokio::task::spawn_blocking`, which schedules onto the ambient\n        // runtime and cannot be awaited from a sync/Drop context) and `.join()`\n        // it so cleanup fully completes before `cleanup_db` returns. This is\n        // safe to call from `Drop::drop` since nothing here is `.await`ed on\n        // the caller's runtime.\n        std::thread::spawn(move || {\n            let rt = tokio::runtime::Runtime::new().expect(\"create cleanup runtime\");\n\n            rt.block_on(async {\n                let pool = Pool::<Postgres>::connect(&connection_string)\n                    .await\n                    .expect(\"db connection should success\");\n                let query = format!(\"drop database if exists {table_name};\");\n                sqlx::query(AssertSqlSafe(query))\n                    .execute(&pool)\n                    .await\n                    .expect(\"Drop database\");\n            });\n        })\n        .join()\n        .expect(\"db cleanup thread panicked\");\n    }\n}\n\npub struct SqliteTest {\n    connection_string: String,\n    db_folder: PathBuf,\n    _tree: tree_fs::Tree, // Keep the tree alive while the test runs\n}\n\nimpl SqliteTest {\n    /// Prepare new `SQLite` connection string.\n    ///\n    /// # Errors\n    /// Returns an error if could not prepare the connection string","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/loco-rs/loco/blob/23639d1e360dbc618073642b507d6f8664adbaff/src/testing/db.rs#L134-L170","documentation":"The `DROP DATABASE IF EXISTS {table_name};` statement executed during cleanup failed. Since it is IF EXISTS, 'not found' is not the issue — this fires on server-side SQL errors such as the database being in use (other connections), permission denied, or the server failing the command, panicking the cleanup thread.","triggerScenarios":"Other connections still attached to the test database (idle pools, background workers) causing 'database is being accessed by other users'; insufficient privilege to drop; server-side error on the drop statement.","commonSituations":"Postgres refusing DROP DATABASE while sessions are open in CI; a crashed test leaving a connection alive; managed Postgres where the test user lacks ownership of the DB.","solutions":["Ensure all pools/connections to the test DB are closed before cleanup (drop the test pool, no background tasks holding connections)","Use `DROP DATABASE ... WITH (FORCE)` (Postgres 13+) or terminate backends first: `SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '...'`","Grant the cleanup user ownership/CREATEDB rights on the test database","Retry cleanup after a short delay to let connections drain"],"exampleFix":"// before\ndrop database if exists {table_name};\n// after (requires PG14+ sqlx support)\ndrop database if exists {table_name} with (force);","handlingStrategy":"retry","validationCode":"// Terminate lingering backends before dropping\n// SELECT pg_terminate_backend(pid) FROM pg_stat_activity\n//  WHERE datname = 'loco_test_x' AND pid <> pg_backend_pid();","typeGuard":null,"tryCatchPattern":"// Retry the drop once after a short drain\n// for attempt in 0..2 {\n//     if try_drop(&name).await.is_ok() { break; }\n//     tokio::time::sleep(Duration::from_millis(200)).await;\n// }","preventionTips":["Drop pools holding the test DB before cleanup","Use DROP DATABASE ... WITH (FORCE) on Postgres 13+","Grant ownership of test DBs to the cleanup user","Keep background workers from holding test DB connections at teardown"],"tags":["rust","postgres","database","testing","sql"],"backgroundTag":"database-query-failed","analyzedSha":"23639d1e360dbc618073642b507d6f8664adbaff","analyzedAt":"2026-09-12T01:47:20.769Z","contentChangedAt":"2026-09-12T01:47:20.769Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}