tinyhumansai/openhuman · error

session store mutex poisoned

Error message

session store mutex poisoned

What it means

Mutex poisoning on the claude-code session store's inner mutex (workspace/claude-code-sessions.json mapping thread_id -> CC session UUID): a panic during get/set while holding the lock poisons it, and a subsequent lock() expect fails. Session persistence for the Claude Code provider becomes unusable until restart; the original panic is the root cause.

Source

Thrown at src/openhuman/inference/provider/claude_code/session_store.rs:44

}

impl SessionStore {
    /// Open (or initialize) the session store at `workspace/claude-code-sessions.json`.
    pub fn open(workspace_dir: &Path) -> Self {
        let path = workspace_dir.join("claude-code-sessions.json");
        let inner = std::fs::read_to_string(&path)
            .ok()
            .and_then(|s| serde_json::from_str::<StoreFile>(&s).ok())
            .unwrap_or_default();
        Self {
            path,
            inner: Mutex::new(inner),
        }
    }

    /// Lookup an existing CC session UUID for `thread_id`.
    pub fn get(&self, thread_id: &str) -> Option<String> {
        let guard = self.inner.lock().expect("session store mutex poisoned");
        guard.sessions.get(thread_id).cloned()
    }

    /// Persist a thread → UUID mapping.
    pub fn set(&self, thread_id: &str, uuid: &str) -> std::io::Result<()> {
        let mut guard = self.inner.lock().expect("session store mutex poisoned");
        guard
            .sessions
            .insert(thread_id.to_string(), uuid.to_string());
        let serialized = serde_json::to_string_pretty(&*guard).map_err(std::io::Error::other)?;
        if let Some(parent) = self.path.parent() {
            std::fs::create_dir_all(parent)?;
        }
        std::fs::write(&self.path, serialized)
    }
}

/// Random RFC-4122 v4 UUID, formatted lower-case with hyphens.

View on GitHub (pinned to 7491200858)

Solutions

  1. Find the earlier panic in the logs that poisoned the store lock
  2. Use lock().unwrap_or_else(|e| e.into_inner()) — the JSON map is still structurally valid after a panic between operations
  3. Keep lock scope minimal around the read-modify-write in set()
Defensive patterns

Strategy: try-catch

When it happens

Trigger: Thrown at src/openhuman/inference/provider/claude_code/session_store.rs:44 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/ae87e3d19d7b384a. Report an issue: GitHub.