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

  1. Pass the callable itself, not a call result: add_tool("search", search_tool) not add_tool("search", search_tool()).
  2. If wrapping, pass a lambda/partial: add_tool("search", lambda q: run_search(q)).
  3. Print type(tool) before the call to confirm it is a function/method/functor.
  4. 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

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


AI-assisted analysis of Fosowl/agenticSeek@ae57a23577 (2026-08-30). Data as JSON: /api/errors/a295d9da8641dc91. Report an issue: GitHub.