SeaQL/sea-orm · error
Fail to acquire mocker
Error message
Fail to acquire mocker
What it means
The MockDatabase connector calls .lock().expect("Fail to acquire mocker") on a Mutex guarding the mocker. If another thread panicked while holding the lock, the mutex is poisoned and lock() returns Err, causing this panic. It indicates a poisoned-lock situation, not a logic error in your test code itself.
Source
Thrown at src/driver/mock.rs:142
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 — inspect the panic message from the first failing thread/test.
- Give each test its own MockDatabase/connector instead of sharing one across threads.
- Use lock().unwrap_or_else(|p| p.into_inner()) if you prefer to recover from poisoning rather than panic.
- Avoid panicking assertions inside mock callbacks; return errors instead.
Example fix
// before
self.mocker.lock().expect("Fail to acquire mocker").get_database_backend()
// after
self.mocker.lock().unwrap_or_else(|poisoned| poisoned.into_inner()).get_database_backend() Defensive patterns
Strategy: validation
Validate before calling
// Before using the shared mock connector, check the lock is not poisoned: assert!(!connector.mocker.is_poisoned(), "mocker lock poisoned by an earlier panic");
Type guard
fn mocker_healthy(c: &MockDatabaseConnector) -> bool { !c.mocker.is_poisoned() } Try / catch
let backend = std::panic::catch_unwind(AssertUnwindSafe(|| connector.get_database_backend()))
.unwrap_or_else(|_| DbBackend::Postgres); // fallback for poisoned lock Prevention
- Never share one MockDatabase across parallel tests
- Avoid panicking assertions inside mock callbacks
- Run the first failing test serially to expose the poisoning panic
- Check Mutex::is_poisoned in test teardown to detect root panics early
When it happens
Trigger: Calling MockDatabaseConnector::get_database_backend() after any thread panicked while holding the mocker mutex (e.g. a panicked assert inside a mock callback).
Common situations: Parallel tests sharing one MockDatabase connector where one test panics mid-mock; a mock closure that unwraps on unexpected SQL, poisoning the lock for all subsequent calls.
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/e620bbbab54f8417.
Report an issue: GitHub.