{"record":{"id":"b61f2fe13f82a398","repo":"tinyhumansai/openhuman","slug":"embedder-tool-hook-arguments-poisoned","errorCode":null,"errorMessage":"embedder tool-hook arguments poisoned","messagePattern":"embedder tool-hook arguments poisoned","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/openhuman/agent/tinyagents/middleware.rs","lineNumber":1538,"sourceCode":"            arguments: call.arguments.clone(),\n            success: None,\n            duration_ms: None,\n        };\n        for hook in &self.hooks {\n            hook.before_tool(&context).await.map_err(|error| {\n                tinyagents::error::TinyAgentsError::Tool(format!(\n                    \"tool hook '{}' denied {}: {error:#}\",\n                    hook.name(),\n                    context.tool_name\n                ))\n            })?;\n        }\n        // Cache the (already-recovered) arguments only once every hook approved\n        // the call: a vetoed call never reaches `after_tool`, so storing it here\n        // would leak a cache entry for the turn.\n        self.arguments_by_call_id\n            .lock()\n            .expect(\"embedder tool-hook arguments poisoned\")\n            .insert(call.id.clone(), call.arguments.clone());\n        Ok(())\n    }\n\n    async fn after_tool(\n        &self,\n        _ctx: &mut RunContext<()>,\n        _state: &(),\n        result: &mut TaToolResult,\n    ) -> TaResult<()> {\n        let arguments = self\n            .arguments_by_call_id\n            .lock()\n            .expect(\"embedder tool-hook arguments poisoned\")\n            .remove(&result.call_id)\n            .unwrap_or(serde_json::Value::Null);\n        let context = crate::openhuman::agent::hooks::ToolHookContext {\n            event: crate::openhuman::agent::hooks::ToolHookEvent::PostToolUse,","sourceCodeStart":1520,"sourceCodeEnd":1556,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/agent/tinyagents/middleware.rs#L1520-L1556","documentation":"Mutex poisoning on the shared tool-arguments cache in the tinyagents middleware: a panic in a hook (before_tool/after_tool) or another thread while holding the arguments mutex poisons it, and the next lock() in the embedder tool-hook path expects success. The denial/error text shown is a symptom; the original panic earlier in the log is the cause.","triggerScenarios":"Thrown at src/openhuman/agent/tinyagents/middleware.rs:1538 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Locate the poisoning panic in the logs (a hook that unwound mid-lock) and fix it","Use lock().unwrap_or_else(|e| e.into_inner()) to salvage cached arguments when poison is tolerable","Isolate each hook's body so one panicking hook cannot unwind through the mutex guard"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}