loco-rs/loco · error

Could not delete sqlite test db

Error message

Could not delete sqlite test db

What it means

cleanup_db removes the temporary sqlite test database folder with std::fs::remove_dir_all and .expect()s on the result. If the directory cannot be deleted (files locked by an open connection, missing permissions, or the folder already removed), the expect panics with 'Could not delete sqlite test db'. This runs during test teardown, so the panic surfaces after the test body itself.

Solutions

  1. Ensure all DB connections are dropped/closed before cleanup_db runs (scope the pool/connection, or call explicit close).
  2. Run DB-backed tests with #[serial] (or a test mutex) so cleanup never races an open connection.
  3. Check permissions/ownership of the temp folder and the running user (CI: run with adequate tmp dir rights).
  4. Delete stale db_still_folder manually and rerun; add a tolerant teardown (match on the remove result) if a leftover dir is acceptable.
  5. On Windows, close sqlite connections or configure sqlite temp_store/journal settings to avoid lingering file handles.

Example fix

// before
fn cleanup_db(&self) {
    std::fs::remove_dir_all(&self.db_folder).expect("Could not delete sqlite test db");
}
// after
fn cleanup_db(&self) {
    if let Err(e) = std::fs::remove_dir_all(&self.db_folder) {
        eprintln!("warning: failed to remove test db dir {:?}: {e}", self.db_folder);
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before teardown
assert!(std::path::Path::new(&self.db_folder).exists(), "test db dir missing");
// ensure connections are closed: drop(pool) and let scope end before cleanup

Try / catch

match std::fs::remove_dir_all(&db_folder) {
    Ok(()) => {}
    Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
    Err(e) => eprintln!("cleanup warning: {e}"),
}

Prevention

When it happens

Trigger: Calling the sqlite TestHost's cleanup_db() when db_still_folder is still held open by an sqlite connection (Windows file locking is notorious), when the process lacks write permission on the parent directory, or when the folder was already deleted by another test/parallel run.

Common situations: Running #[serial]-less sqlite tests in parallel so one test's connection still holds the db file while another cleans up; CI containers running as non-root with restrictive temp-dir permissions; killing a previous test run that left a stale lock; Windows developers hitting OS-level file-in-use locks.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


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

Appendix: source

Thrown at src/testing/db.rs:203

                db_name,
                &tree.root.join("test.sqlite").display().to_string(),
            ),
            db_folder: tree.root.clone(),
            _tree: tree,
        })
    }
}

impl TestSupport for SqliteTest {
    fn get_connection_str(&self) -> &str {
        &self.connection_string
    }
    fn init_db<'a>(&'a self) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
        Box::pin(async move {})
    }

    fn cleanup_db(&self) {
        std::fs::remove_dir_all(&self.db_folder).expect("Could not delete sqlite test db");
    }
}

pub struct Any {
    connection_string: String,
}
impl Any {
    #[must_use]
    pub fn new(conn_str: &str) -> Self {
        Self {
            connection_string: conn_str.to_string(),
        }
    }
}

impl TestSupport for Any {
    fn get_connection_str(&self) -> &str {
        &self.connection_string

View on GitHub (pinned to 23639d1e36)