tinyhumansai/openhuman · error · anyhow::Error
claude-code semaphore closed: {e}
Error message
claude-code semaphore closed: {e} What it means
Acquiring the concurrency permit that caps simultaneous Claude Code processes failed because the semaphore was closed. The permit is released per turn; a closed semaphore means the provider instance is being torn down while a chat request is still arriving — an invariant/lifecycle error, not load-related.
Source
Thrown at src/openhuman/inference/provider/claude_code/mod.rs:171
"[claude-code] `claude` CLI at {} unusable: {}",
path,
reason
),
}
}
async fn run_chat(
&self,
request: ChatRequest<'_>,
model_override: Option<&str>,
) -> anyhow::Result<ChatResponse> {
// Cap concurrent CC processes.
let _permit = self
.semaphore
.clone()
.acquire_owned()
.await
.map_err(|e| anyhow::anyhow!("claude-code semaphore closed: {e}"))?;
// Extract system prompt + thread_id from the request.
let append_system_prompt = request
.messages
.iter()
.find(|m| m.role == "system")
.map(|m| m.content.clone());
// OpenHuman doesn't pass thread_id directly through ChatRequest yet
// (Phase 4 will). For Phase 2 we key sessions on a stable hash of
// the conversation so /resume kicks in across consecutive turns.
let thread_id = thread_key_from_messages(request.messages);
let model = model_override.unwrap_or(&self.model).to_string();
let turn = driver::TurnContext {
bin_path: self.bin_path.clone(),
workspace_dir: self.workspace_dir.clone(),View on GitHub (pinned to 7491200858)
Solutions
- Ensure the provider is not used after shutdown
- Check for requests racing provider teardown
Defensive patterns
Strategy: try-catch
When it happens
Trigger: Thrown at src/openhuman/inference/provider/claude_code/mod.rs:171 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/8a0ca5f770d14405.
Report an issue: GitHub.