Fosowl/agenticSeek · error · TypeError
Tool must be a callable object (a method)
Error message
Tool must be a callable object (a method)
What it means
add_tool() validates that the value passed as `tool` is callable before storing it in self.tools; otherwise later agent execution would crash when invoking it. It raises TypeError immediately at registration time to fail fast. Only `callable()` is checked — the `name` key itself is not validated.
Source
Thrown at sources/agents/agent.py:94
@property
def get_status_message(self) -> str:
return self.status_message
@property
def get_tools(self) -> dict:
return self.tools
@property
def get_success(self) -> bool:
return self.success
def get_blocks_result(self) -> list:
return self.blocks_result
def add_tool(self, name: str, tool: Callable) -> None:
if not callable(tool):
raise TypeError("Tool must be a callable object (a method)")
self.tools[name] = tool
def get_tools_name(self) -> list:
"""
Get the list of tools names.
"""
return list(self.tools.keys())
def get_tools_description(self) -> str:
"""
Get the list of tools names and their description.
"""
description = ""
for name in self.get_tools_name():
description += f"{name}: {self.tools[name].description}\n"
return description
def load_prompt(self, file_path: str) -> str:View on GitHub (pinned to ae57a23577)
Solutions
- Pass the callable itself, not a call result: add_tool("search", search_tool) not add_tool("search", search_tool()).
- If wrapping, pass a lambda/partial: add_tool("search", lambda q: run_search(q)).
- Print type(tool) before the call to confirm it is a function/method/functor.
- If you only have a spec/dict, wrap it in a real function before registering.
Example fix
// before
agent.add_tool("search", search_tool()) # TypeError
// after
agent.add_tool("search", search_tool) Defensive patterns
Strategy: type-guard
Validate before calling
def safe_add_tool(agent, name, tool):
if not callable(tool):
raise TypeError(f"{name!r} must be a callable, got {type(tool).__name__}")
agent.add_tool(name, tool) Type guard
def is_callable_tool(tool) -> bool:
return callable(tool) # functions, methods, lambdas, functors with __call__ Try / catch
try:
agent.add_tool(name, tool)
except TypeError as e:
if "must be a callable" in str(e):
raise ValueError(f"Tool '{name}' is not callable; pass the function itself, not its result") from e
raise Prevention
- Never write add_tool("x", fn()) — parentheses invoke; pass fn itself.
- If a tool needs arguments, register a lambda or functools.partial instead of the bound result.
- Add a unit test mirroring test_add_tool_rejects_non_callable for each tool registry helper.
- Log type(tool) at registration sites during development to catch accidental call results.
When it happens
Trigger: Calling agent.add_tool(name, tool) where tool is not callable, e.g. a string, dict, None, or the result of calling a function instead of the function itself (tool() vs tool). As the test names show, non-callables are rejected intentionally.
Common situations: Passing a function's return value instead of the function (missing @ or extra parentheses); passing a tool described as a dict/JSON spec rather than a Python callable; passing a method name string; typos leaving the variable None.
Related errors
- Model not set
- Ollama connection failed. is the server running ?
- Prompt file not found at path: {file_path}
- Permission denied to read prompt file at path: {file_path}
- Failed to initialize browser: {str(e)}
AI-assisted analysis of Fosowl/agenticSeek@ae57a23577 (2026-08-30).
Data as JSON: /api/errors/a295d9da8641dc91.
Report an issue: GitHub.