SeaQL/sea-orm · error

Fail to acquire mocker

Error message

Fail to acquire mocker

What it means

`MockDatabaseConnection::get_database_backend` locks the internal `Mutex<Box<dyn MockDatabaseTrait>>` and panics with "Fail to acquire mocker" if the lock is poisoned — i.e. a previous thread panicked while holding the mocker lock. Note that sibling methods like `execute`/`query_all` use `.map_err(...)` and return `DbErr`, but this one (plus `begin`/`commit`/`rollback`) uses `expect`, so a poisoned lock aborts the process instead of returning an error.

Source

Thrown at sea-orm-sync/src/driver/mock.rs:141

            execute_counter: AtomicUsize::new(0),
            query_counter: AtomicUsize::new(0),
            mocker: Mutex::new(Box::new(m)),
        }
    }

    pub(crate) fn get_mocker_mutex(&self) -> &Mutex<Box<dyn MockDatabaseTrait>> {
        &self.mocker
    }

    /// Get the [DatabaseBackend](crate::DatabaseBackend) being used by the [MockDatabase]
    ///
    /// # Panics
    ///
    /// Will panic if the lock cannot be acquired.
    pub fn get_database_backend(&self) -> DbBackend {
        self.mocker
            .lock()
            .expect("Fail to acquire mocker")
            .get_database_backend()
    }

    /// Execute the SQL statement in the [MockDatabase]
    #[instrument(level = "trace", skip(statement))]
    pub fn execute(&self, statement: Statement) -> Result<ExecResult, DbErr> {
        debug_print!("{}", statement);
        let counter = self.execute_counter.fetch_add(1, Ordering::SeqCst);
        self.mocker
            .lock()
            .map_err(exec_err)?
            .execute(counter, statement)
    }

    /// Return one [QueryResult] if the query was successful
    #[instrument(level = "trace", skip(statement))]
    pub fn query_one(&self, statement: Statement) -> Result<Option<QueryResult>, DbErr> {
        debug_print!("{}", statement);

View on GitHub (pinned to e29bcd1b41)

Solutions

  1. Fix the original panic that poisoned the lock — look for the first panic in the test output (often a failing mock assertion).
  2. Use `MockDatabaseConnection::get_mocker_mutex()` with `lock().unwrap_or_else(|p| p.into_inner())` if you need lock-free-after-poison access in your own code.
  3. Avoid panicking inside mock callback/expectation code; return `Err` values from `MockDatabase` trait methods instead.
  4. Patch the call site defensively: replace `.expect(...)` with `.map_err(...)`/recovery via `PoisonError::into_inner`, matching the `execute`/`query_all` pattern.
  5. Isolate each mock database per test so one panicking test cannot poison a shared mocker.

Example fix

// before
pub fn get_database_backend(&self) -> DbBackend {
    self.mocker.lock().expect("Fail to acquire mocker").get_database_backend()
}
// after — tolerate a poisoned lock instead of panicking
pub fn get_database_backend(&self) -> DbBackend {
    self.mocker
        .lock()
        .unwrap_or_else(|poisoned| poisoned.into_inner())
        .get_database_backend()
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Check the mock connection is usable (lock not poisoned) before queries
fn mock_backend_available(conn: &MockDatabaseConnection) -> bool {
    !conn.get_mocker_mutex().is_poisoned()
}

Type guard

fn mocker_lock(conn: &MockDatabaseConnection) -> Option<MutexGuard<'_, Box<dyn MockDatabaseTrait>>> {
    conn.get_mocker_mutex().lock().ok()
}

Try / catch

let backend = std::panic::catch_unwind(AssertUnwindSafe(|| conn.get_database_backend()))
    .unwrap_or_else(|_| {
        eprintln!("mock mocker lock poisoned; recreating MockDatabase");
        rebuild_mock_connection()
    });

Prevention

When it happens

Trigger: Calling `get_database_backend()` (directly or via `DatabaseBackend`/connection helpers) on a `DatabaseConnection` backed by a `MockDatabase` whose mocker mutex was poisoned by an earlier panic in another method (e.g. a user-panic inside `MockDatabase::exec`/`query` callbacks or assert code), or reentrant locking from the same thread.

Common situations: Almost always seen in tests: a mock expectation closure panics (assertion failure) while holding the lock, poisoning it; subsequent calls to `get_database_backend` panic with this message. Also appears when the mock connection is shared across threads in sync code and a worker panics mid-query.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of SeaQL/sea-orm@e29bcd1b41 (2026-09-10). Data as JSON: /api/errors/c549c4fc2d3700f8. Report an issue: GitHub.