{"record":{"id":"3df1f606d5ec2cb9","repo":"janhq/jan","slug":"agenttoolserror-message","errorCode":null,"errorMessage":"AgentToolsError: {message}","messagePattern":"AgentToolsError: (.+?)","errorType":"error_code","errorClass":"AgentToolsError","httpStatus":null,"severity":"error","filePath":"src-tauri/plugins/tauri-plugin-agent-tools/src/commands.rs","lineNumber":48,"sourceCode":"//! Note some command names match built-in tool names (`skill_list`,\n//! `memory_list`). The commands are the *management* surface; the tools are what\n//! the model calls. They are separate namespaces.\n\nuse std::path::{Path, PathBuf};\n\nuse serde::Serialize;\n\nuse crate::memory;\nuse crate::permissions::ToolPermissions;\nuse crate::preview::{self, PreviewRoots};\nuse crate::skills::{self, SkillMeta};\nuse crate::tools::gate::{self, Decision, PromptKind, SessionGrants};\nuse crate::tools::jail;\nuse crate::tools::{handlers, lookup, schema, ImageContentPart, ToolContext};\nuse crate::workspace;\n\n#[derive(Debug, Clone, Serialize, thiserror::Error)]\n#[error(\"AgentToolsError: {message}\")]\npub struct AgentToolsError {\n    pub message: String,\n}\n\nimpl From<String> for AgentToolsError {\n    /// Strips the core's `ERROR:` tool-protocol prefix; it is meaningful to the\n    /// model, but noise in a dialog.\n    fn from(message: String) -> Self {\n        let message = message\n            .strip_prefix(\"ERROR:\")\n            .unwrap_or(&message)\n            .trim()\n            .to_string();\n        Self { message }\n    }\n}\n\n/// Outcome of a built-in tool execution.","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/janhq/jan/blob/7205d770c1e097c3daf35a911176410e93bc5564/src-tauri/plugins/tauri-plugin-agent-tools/src/commands.rs#L30-L66","documentation":"AgentToolsError is the plugin's unified error type, serialized via thiserror as 'AgentToolsError: {message}'. From<String> strips the core's 'ERROR:' tool-protocol prefix before storing the message, so errors crossing the tool protocol boundary are normalized into this struct.","triggerScenarios":"Any agent-tools command handler (via commands.rs) returns Err containing a string — often converted through From<String> after stripping the 'ERROR:' prefix — including gate denials, jail violations, schema/lookup failures, or workspace errors surfaced by handlers.","commonSituations":"A tool call is rejected by the permission gate (missing session grants), a command violates the sandbox/jail, or a handler returns an error string that the command layer wraps into AgentToolsError and forwards to the client.","solutions":["Read the message field after the 'AgentToolsError: ' prefix — the underlying cause is preserved there.","If the message indicates permission denial, grant the required tool/session permissions before retrying.","If it indicates a sandbox/jail violation, adjust the workspace/jail configuration to permit the attempted path or command.","Fix the caller-side tool arguments if the message reflects schema validation failure, and retry the tool call."],"exampleFix":"// before (Rust handler)\nreturn Err(\"ERROR: tool 'fs_write' not permitted\".into());\n// after — agent side\nmatch result {\n  Err(AgentToolsError { message }) if message.contains(\"not permitted\") => {\n    request_session_grant(\"fs_write\")?;\n    retry_tool_call()\n  }\n  other => other,\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match agent_tools_call(args) {\n  Err(e) if e.to_string().starts_with(\"AgentToolsError: \") => {\n    let msg = e.to_string().trim_start_matches(\"AgentToolsError: \").to_string();\n    if msg.contains(\"not permitted\") { request_grant_and_retry()?; }\n    else { return Err(anyhow!(msg)); }\n  }\n  other => other,\n}","preventionTips":["Check required session grants/permissions before invoking gated tools.","Keep tool arguments within the declared JSON schema to avoid schema-level rejections.","Configure jail/workspace paths up front so sandboxed operations are allowed.","Parse the message after the 'AgentToolsError: ' prefix rather than matching the whole string."],"tags":["rust","tool-protocol","error-wrapper"],"backgroundTag":"api-error-response","analyzedSha":"7205d770c1e097c3daf35a911176410e93bc5564","analyzedAt":"2026-09-17T14:27:30.100Z","contentChangedAt":"2026-09-17T14:27:30.100Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}