loco-rs/loco · error

Drop database

Error message

Drop database

What it means

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.

Solutions

  1. Ensure all pools/connections to the test DB are closed before cleanup (drop the test pool, no background tasks holding connections)
  2. Use `DROP DATABASE ... WITH (FORCE)` (Postgres 13+) or terminate backends first: `SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '...'`
  3. Grant the cleanup user ownership/CREATEDB rights on the test database
  4. Retry cleanup after a short delay to let connections drain

Example fix

// before
drop database if exists {table_name};
// after (requires PG14+ sqlx support)
drop database if exists {table_name} with (force);
Defensive patterns

Strategy: retry

Validate before calling

// Terminate lingering backends before dropping
// SELECT pg_terminate_backend(pid) FROM pg_stat_activity
//  WHERE datname = 'loco_test_x' AND pid <> pg_backend_pid();

Try / catch

// Retry the drop once after a short drain
// for attempt in 0..2 {
//     if try_drop(&name).await.is_ok() { break; }
//     tokio::time::sleep(Duration::from_millis(200)).await;
// }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


AI-assisted analysis of loco-rs/loco@23639d1e36 (2026-09-12). Data as JSON: /api/errors/9a13fa5b252b47c0. Report an issue: GitHub.

Appendix: source

Thrown at src/testing/db.rs:152

        // Run the drop on a dedicated OS thread with its own runtime (not
        // `tokio::task::spawn_blocking`, which schedules onto the ambient
        // runtime and cannot be awaited from a sync/Drop context) and `.join()`
        // it so cleanup fully completes before `cleanup_db` returns. This is
        // safe to call from `Drop::drop` since nothing here is `.await`ed on
        // the caller's runtime.
        std::thread::spawn(move || {
            let rt = tokio::runtime::Runtime::new().expect("create cleanup runtime");

            rt.block_on(async {
                let pool = Pool::<Postgres>::connect(&connection_string)
                    .await
                    .expect("db connection should success");
                let query = format!("drop database if exists {table_name};");
                sqlx::query(AssertSqlSafe(query))
                    .execute(&pool)
                    .await
                    .expect("Drop database");
            });
        })
        .join()
        .expect("db cleanup thread panicked");
    }
}

pub struct SqliteTest {
    connection_string: String,
    db_folder: PathBuf,
    _tree: tree_fs::Tree, // Keep the tree alive while the test runs
}

impl SqliteTest {
    /// Prepare new `SQLite` connection string.
    ///
    /// # Errors
    /// Returns an error if could not prepare the connection string

View on GitHub (pinned to 23639d1e36)