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
- Fix the original panic that poisoned the lock — look for the first panic in the test output (often a failing mock assertion).
- 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.
- Avoid panicking inside mock callback/expectation code; return `Err` values from `MockDatabase` trait methods instead.
- Patch the call site defensively: replace `.expect(...)` with `.map_err(...)`/recovery via `PoisonError::into_inner`, matching the `execute`/`query_all` pattern.
- 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
- Fix the root panic that poisoned the lock — later panics are secondary symptoms
- Create a fresh MockDatabase per test so poisoning cannot leak between tests
- Never panic inside mock expectation/callback code; return DbErr instead
- Avoid calling back into the connection from within MockDatabaseTrait methods (reentrant lock)
- Use is_poisoned() checks or unwrap_or_else(PoisonError::into_inner) in custom helper code
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
- Fail to acquire mocker
- Failed to acquire mocker
- Not mock connection
- There is no open transaction to commit
- There is no open transaction to rollback
AI-assisted analysis of SeaQL/sea-orm@e29bcd1b41 (2026-09-10).
Data as JSON: /api/errors/c549c4fc2d3700f8.
Report an issue: GitHub.