SeaQL/sea-orm · error

Fail to acquire mocker

Error message

Fail to acquire mocker

What it means

into_transaction_log drains the mock connection's transaction log under a std Mutex. If the mocker mutex cannot be locked (already held by another thread, or poisoned by a prior panic), .lock().expect(...) panics with 'Fail to acquire mocker'. The method's doc comment explicitly warns of this panic.

Source

Thrown at sea-orm-sync/src/database/db_connection.rs:549

    /// Panics if [DbConn] is not a mock connection.
    pub fn as_mock_connection(&self) -> &crate::MockDatabaseConnection {
        match &self.inner {
            DatabaseConnectionType::MockDatabaseConnection(mock_conn) => mock_conn,
            _ => panic!("Not mock connection"),
        }
    }

    /// Get the transaction log as a collection Vec<[crate::Transaction]>
    ///
    /// # Panics
    ///
    /// Panics if the mocker mutex is being held by another thread.
    pub fn into_transaction_log(self) -> Vec<crate::Transaction> {
        let mut mocker = self
            .as_mock_connection()
            .get_mocker_mutex()
            .lock()
            .expect("Fail to acquire mocker");
        mocker.drain_transaction_log()
    }
}

#[cfg(feature = "proxy")]
impl DatabaseConnection {
    /// Generate a database connection for testing the Proxy database
    ///
    /// # Panics
    ///
    /// Panics if [DbConn] is not a proxy connection.
    pub fn as_proxy_connection(&self) -> &crate::ProxyDatabaseConnection {
        match &self.inner {
            DatabaseConnectionType::ProxyDatabaseConnection(proxy_conn) => proxy_conn,
            _ => panic!("Not proxy connection"),
        }
    }
}

View on GitHub (pinned to e29bcd1b41)

Solutions

  1. Ensure only one thread calls into_transaction_log at a time (drain once per connection)
  2. Fix the earlier panic that poisoned the mutex before draining the log
  3. Recover from poisoning with poisoned.into_inner() if the log is still needed
  4. Guard the mock connection with your own synchronization in tests

Example fix

// before
let log = db.into_transaction_log(); // panics if mutex held/poisoned
// after
let mocker = db.as_mock_connection().get_mocker_mutex();
let log = { let m = mocker.lock().unwrap_or_else(|e| e.into_inner()); m.drain_transaction_log() };
Defensive patterns

Strategy: try-catch

Validate before calling

fn can_drain(db: &DatabaseConnection) -> bool {
    db.as_mock_connection().get_mocker_mutex().try_lock().is_ok()
}

Try / catch

// recover from poisoned lock instead of expect
let mocker = db.as_mock_connection().get_mocker_mutex();
let mut m = match mocker.lock() {
    Ok(g) => g,
    Err(poisoned) => poisoned.into_inner(), // recover after fixing the panicking thread
};
let log = m.drain_transaction_log();

Prevention

When it happens

Trigger: Calling DatabaseConnection::into_transaction_log() on a mock connection while another thread holds the mocker mutex, or after a previous panic while holding the lock poisoned the mutex.

Common situations: Parallel tests sharing one MockDatabase connection; a test that panicked earlier while holding the lock, poisoning it for subsequent callers.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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