janhq/jan · error · AgentToolsError
AgentToolsError
Error message
AgentToolsError: {message} What it means
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.
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.
Example fix
// before (Rust handler)
return Err("ERROR: tool 'fs_write' not permitted".into());
// after — agent side
match result {
Err(AgentToolsError { message }) if message.contains("not permitted") => {
request_session_grant("fs_write")?;
retry_tool_call()
}
other => other,
} Defensive patterns
Strategy: try-catch
Try / catch
match agent_tools_call(args) {
Err(e) if e.to_string().starts_with("AgentToolsError: ") => {
let msg = e.to_string().trim_start_matches("AgentToolsError: ").to_string();
if msg.contains("not permitted") { request_grant_and_retry()?; }
else { return Err(anyhow!(msg)); }
}
other => other,
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of janhq/jan@7205d770c1 (2026-09-17).
Data as JSON: /api/errors/3df1f606d5ec2cb9.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/plugins/tauri-plugin-agent-tools/src/commands.rs:48
//! Note some command names match built-in tool names (`skill_list`,
//! `memory_list`). The commands are the *management* surface; the tools are what
//! the model calls. They are separate namespaces.
use std::path::{Path, PathBuf};
use serde::Serialize;
use crate::memory;
use crate::permissions::ToolPermissions;
use crate::preview::{self, PreviewRoots};
use crate::skills::{self, SkillMeta};
use crate::tools::gate::{self, Decision, PromptKind, SessionGrants};
use crate::tools::jail;
use crate::tools::{handlers, lookup, schema, ImageContentPart, ToolContext};
use crate::workspace;
#[derive(Debug, Clone, Serialize, thiserror::Error)]
#[error("AgentToolsError: {message}")]
pub struct AgentToolsError {
pub message: String,
}
impl From<String> for AgentToolsError {
/// Strips the core's `ERROR:` tool-protocol prefix; it is meaningful to the
/// model, but noise in a dialog.
fn from(message: String) -> Self {
let message = message
.strip_prefix("ERROR:")
.unwrap_or(&message)
.trim()
.to_string();
Self { message }
}
}
/// Outcome of a built-in tool execution.View on GitHub (pinned to 7205d770c1)