Hmbown/CodeWhale · error

model catalog test lock

Error message

model catalog test lock

What it means

A test-support lock name, not a runtime error: TEST_CATALOG_LOCK is a LazyLock<Mutex<()>> that tests acquire (via test_catalog_lock) to serialize catalog tests that touch the shared state-dir cache file (OPENROUTER_CACHE_FILE under resolve_state_dir("catalog")). It exists so concurrent tests don't race on load_cached/save of the same on-disk cache; a failure would only be a poisoned-lock panic in tests.

Solutions

  1. Keep every test that reads or writes the shared catalog cache inside the test_catalog_lock guard
  2. If a lock-poisoning panic occurs, isolate which test panicked while holding the lock and fix that test
  3. Point catalog tests at an isolated temp state dir where possible so the global lock is unnecessary
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at crates/models/src/model_catalog.rs:206 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/5232fc82b6da4152. Report an issue: GitHub.

Appendix: source

Thrown at crates/models/src/model_catalog.rs:206

}

fn catalog_cache_read_path() -> Result<PathBuf> {
    Ok(codewhale_config::resolve_state_dir("catalog")?.join(OPENROUTER_CACHE_FILE))
}

pub fn load_cached() -> Option<CatalogCache> {
    let path = catalog_cache_read_path().ok()?;
    let raw = std::fs::read_to_string(path).ok()?;
    serde_json::from_str(&raw).ok()
}

#[cfg(any(test, feature = "test-support"))]
static TEST_CATALOG_LOCK: std::sync::LazyLock<std::sync::Mutex<()>> =
    std::sync::LazyLock::new(|| std::sync::Mutex::new(()));

#[cfg(any(test, feature = "test-support"))]
pub fn test_catalog_lock() -> std::sync::MutexGuard<'static, ()> {
    TEST_CATALOG_LOCK.lock().expect("model catalog test lock")
}

#[cfg(any(test, feature = "test-support"))]
pub struct ActiveCatalogGuard {
    previous: MergedCatalog,
}

#[cfg(any(test, feature = "test-support"))]
impl Drop for ActiveCatalogGuard {
    fn drop(&mut self) {
        let mut active = active_catalog().write().expect("active catalog write lock");
        *active = self.previous.clone();
    }
}

#[cfg(any(test, feature = "test-support"))]
pub fn replace_active_catalog_for_test(catalog: MergedCatalog) -> ActiveCatalogGuard {
    let mut active = active_catalog().write().expect("active catalog write lock");

View on GitHub (pinned to 433685b202)