Tool execution should fail explicitly when tool is not loaded (not silently)
Summary
When a tool is called that hasn't been activated via load_tool(), the system returns a generic error with zero indication of the root cause:
"error occurred invoking 'edit'"
This is a silent failure mode that wastes significant investigation time. The agent has no way to know:
- The tool exists at all
- The tool needs to be loaded first
- How to load it
Instead, the agent spends dozens of attempts trying to fix the content, whitespace, or matching logic — none of which is the actual problem.
Observed Behavior
Scenario: Calling memorizer__edit without loading it
Step 1: Agent calls search_tools → finds memorizer__edit exists.
Step 2: Agent calls load_tool("memorizer__get") → loads the read tool.
Step 3: Agent calls memorizer__edit(...) → never loaded the edit tool.
Step 4: Every edit attempt returns: "error occurred invoking 'edit'"
Step 5: Agent tries 15+ times with different strings, all silently failing.
The actual problem: memorizer__edit was never loaded. The system should have said:
"Tool 'memorizer__edit' is not loaded. Available tools in server 'memorizer' are: get, get_many, get_project_context, search_memories, update_metadata, delete, archive_memory, restore_memory, move_memory. To use this tool, call load_tool('memorizer__edit') first."
Real-world impact
During investigation of the GlobalReadRoots silent fallback bug, I wasted 15+ iterations trying to edit a memorizer record. The edit wasn't failing due to whitespace, encoding, or content matching — it was failing because I never loaded the edit tool. Each failure looked identical: a generic error with no diagnostic guidance.
This is the same pattern as other silent failures in the codebase (see #1492, #1493, #1494) where missing dependencies or null values are silently dropped instead of logged or erroring explicitly.
Proposed Solutions
Option 1: Explicit error with suggestions (recommended)
When a tool is invoked that hasn't been loaded, return a clear error:
"Tool '{toolName}' is not loaded for server '{serverName}'.
Available tools in this server:
- toolA (description)
- toolB (description)
To use this tool, call: load_tool('{toolName}')
Or search for available tools: search_tools(query: 'all', server: '{serverName}')"
Pros:
- Tells the agent exactly what's wrong
- Tells the agent how to fix it
- Doesn't introduce unexpected behavior (auto-loading dangerous tools)
- Safe and predictable
Cons:
- Requires an extra step (agent must call
load_tool)
Option 2: Auto-load and retry
When a tool is invoked that exists but isn't loaded, automatically load it and retry the call:
"Tool '{toolName}' was not loaded. Automatically loading... [success]
Retrying original call..."
Pros:
- More convenient — one less step for simple tools
- Reduces friction for common workflows
Cons:
- Security risk: Auto-loading a dangerous tool (e.g.,
delete_webhook, shell_execute) could execute unintended operations
- Harder to audit — the agent didn't explicitly load the tool, so intent is unclear
- Potential for loading tools the agent shouldn't have (e.g., tools gated by approval gates)
Option 3: Hybrid (auto-load safe tools only)
Auto-load tools marked as "safe" (read-only, non-destructive) and return explicit errors for dangerous ones:
"Tool '{toolName}' is a destructive operation and requires explicit load.
Call load_tool('{toolName}') before invoking."
Pros:
- Best of both worlds — convenience for safe tools, safety for dangerous ones
- Requires a tool metadata field (e.g.,
IsDestructive, RequiresApproval)
Cons:
- Adds metadata complexity
- Risk of misclassifying a tool as "safe"
Recommendation
Option 1 is the safest and most transparent. It matches the principle of "fail loudly" that should apply across the entire codebase. The agent already knows search_tools and load_tool exist, so the path to resolution is clear.
Related
Tool execution should fail explicitly when tool is not loaded (not silently)
Summary
When a tool is called that hasn't been activated via
load_tool(), the system returns a generic error with zero indication of the root cause:This is a silent failure mode that wastes significant investigation time. The agent has no way to know:
Instead, the agent spends dozens of attempts trying to fix the content, whitespace, or matching logic — none of which is the actual problem.
Observed Behavior
Scenario: Calling
memorizer__editwithout loading itStep 1: Agent calls
search_tools→ findsmemorizer__editexists.Step 2: Agent calls
load_tool("memorizer__get")→ loads the read tool.Step 3: Agent calls
memorizer__edit(...)→ never loaded the edit tool.Step 4: Every edit attempt returns:
"error occurred invoking 'edit'"Step 5: Agent tries 15+ times with different strings, all silently failing.
The actual problem:
memorizer__editwas never loaded. The system should have said:Real-world impact
During investigation of the
GlobalReadRootssilent fallback bug, I wasted 15+ iterations trying to edit a memorizer record. The edit wasn't failing due to whitespace, encoding, or content matching — it was failing because I never loaded the edit tool. Each failure looked identical: a generic error with no diagnostic guidance.This is the same pattern as other silent failures in the codebase (see #1492, #1493, #1494) where missing dependencies or null values are silently dropped instead of logged or erroring explicitly.
Proposed Solutions
Option 1: Explicit error with suggestions (recommended)
When a tool is invoked that hasn't been loaded, return a clear error:
Pros:
Cons:
load_tool)Option 2: Auto-load and retry
When a tool is invoked that exists but isn't loaded, automatically load it and retry the call:
Pros:
Cons:
delete_webhook,shell_execute) could execute unintended operationsOption 3: Hybrid (auto-load safe tools only)
Auto-load tools marked as "safe" (read-only, non-destructive) and return explicit errors for dangerous ones:
Pros:
IsDestructive,RequiresApproval)Cons:
Recommendation
Option 1 is the safest and most transparent. It matches the principle of "fail loudly" that should apply across the entire codebase. The agent already knows
search_toolsandload_toolexist, so the path to resolution is clear.Related
{workspaces_dir}despite GlobalReadRoots