oraios/serena · warning · ToolError
e.get_error_message()
Error message
e.get_error_message()
What it means
Serena's MCP adapter wraps each tool call; when tool.apply_ex raises ToolCallError (with catch_exceptions=False), the adapter converts it to an MCP ToolError whose message is the tool's user-facing error text via e.get_error_message(). This is the standard channel for surfacing tool-level failures (bad arguments, file not found, etc.) to the MCP client.
Source
Thrown at src/serena/mcp.py:101
if docstring.returns and (docstring_returns_descr := docstring.returns.description):
# Only add a space before "Returns" if func_doc is not empty
prefix = " " if func_doc else ""
func_doc = f"{func_doc}{prefix}Returns {docstring_returns_descr.strip().strip('.')}."
# Parse the parameter descriptions from the docstring and add pass its description
# to the parameter schema.
docstring_params = {param.arg_name: param for param in docstring.params}
parameters_properties: dict[str, dict[str, Any]] = parameters["properties"]
for parameter, properties in parameters_properties.items():
if (param_doc := docstring_params.get(parameter)) and param_doc.description:
param_desc = f"{param_doc.description.strip().strip('.') + '.'}"
properties["description"] = param_desc[0].upper() + param_desc[1:]
def execute_fn(**kwargs) -> str:
try:
return tool.apply_ex(log_call=True, catch_exceptions=False, **kwargs)
except ToolCallError as e:
raise ToolError(e.get_error_message()) from e
# Generate human-readable title from snake_case tool name
tool_title = " ".join(word.capitalize() for word in func_name.split("_"))
# Create annotations with appropriate hints based on tool capabilities
can_edit = tool.can_edit()
annotations = ToolAnnotations(
title=tool_title,
readOnlyHint=not can_edit,
destructiveHint=can_edit,
)
super().__init__(
fn=execute_fn,
name=func_name,
description=func_doc,
parameters=parameters,
fn_metadata=func_arg_metadata,View on GitHub (pinned to 7fcbca7e62)
Solutions
- Read the ToolError message — it contains the tool's actual failure description
- Validate inputs (paths exist, symbol name format, regex compiles) before invoking the tool
- Catch tool errors on the MCP client side and retry with corrected arguments
- If the message is unclear, run the tool with log_level=debug to get the underlying stack trace
Example fix
// before (client passes bad path)
{"tool": "read_file", "arguments": {"relative_path": "nope.txt"}}
// after
{"tool": "read_file", "arguments": {"relative_path": "src/nope.txt"}}
// or guard on client side
if os.path.isfile(os.path.join(root, rel_path)):
call_tool("read_file", {"relative_path": rel_path}) Defensive patterns
Strategy: try-catch
Validate before calling
from pathlib import Path
if not (Path(project_root) / relative_path).exists():
raise FileNotFoundError(relative_path) Try / catch
try:
result = call_mcp_tool("read_file", {"relative_path": rel})
except ToolError as e:
logger.warning("tool failed: %s", e)
result = retry_with_corrected_args(e) # message states the actual problem Prevention
- Validate tool arguments (paths, symbol names, regexes) client-side
- Parse the ToolError message — it contains the tool's own failure description
- Retry with corrected arguments rather than treating as fatal
- Enable debug logging when messages are ambiguous
When it happens
Trigger: Any MCP tool execution whose underlying apply_ex raises ToolCallError — e.g. find_symbol on a missing symbol, read/write of a nonexistent path, invalid regex in search tools, tool-specific precondition failures.
Common situations: Client passes a nonexistent file path or symbol name; timeout/no-match conditions raised as ToolCallError; caller-side confusion when the LLM client shows a generic 'tool error' containing the real message.
Related errors
- No active project. Please activate a project first.
- Cannot activate project '{project.project_name}': it require
- Invalid tool name: {tool_name}{caller_context_for_logging}
AI-assisted analysis of oraios/serena@7fcbca7e62 (2026-08-29).
Data as JSON: /api/errors/1c729927c52a26a3.
Report an issue: GitHub.